成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

React Redux: 從文檔看源碼 - Components篇

alphahans / 2383人閱讀

摘要:的作用在文檔中是這么說的給下級(jí)組件中的提供可用的的對象。這個(gè)文件里的主要是被方法引入,并傳給的,算是一個(gè)默認(rèn)的。表示當(dāng)前的名稱。這個(gè)值表示在里面的值。便于控制,同時(shí)某些不需要渲染的,也不會(huì)造成渲染。

注:這篇文章只是講解React Redux這一層,并不包含Redux部分。Redux有計(jì)劃去學(xué)習(xí),等以后學(xué)習(xí)了Redux源碼以后再做分析
注:代碼基于現(xiàn)在(2016.12.29)React Redux的最新版本(5.0.1)

Connect工具類篇(1)
Connect工具類篇(2)

Components篇

在5.0.1版本中,React Redux提供了兩個(gè)Components,一個(gè)是Provider,另外一個(gè)是connectAdvanced。
connect應(yīng)該也算一個(gè),它設(shè)置了一些需要的默認(rèn)值,并調(diào)用、返回connectAdvanced。

Provider

Provider的作用在文檔中是這么說的

給下級(jí)組件中的connect()提供可用的Redux的store對象。一般情況下,如果根組件沒有被包裹,那么你就無法使用connect()方法。

如果你堅(jiān)持不用,你也可以給每一個(gè)需要connect()的組件手動(dòng)傳遞store屬性。但是我們只建議在unit tests或者非完全React的項(xiàng)目中這么用,否則應(yīng)該使用。

Props

根據(jù)文檔,屬性應(yīng)該包含store和children:

store (Redux Store): The single Redux store in your application.

children (ReactElement) The root of your component hierarchy.

先貼一個(gè)使用示例:


  

源碼中也對propTypes做了定義(storeShape請看這里)

Provider.propTypes = {
  store: storeShape.isRequired, // store必須含有storeShape (subscribe, dispatch, getState)
  children: PropTypes.element.isRequired // children必須是一個(gè)React元素
}
之所以文檔中說:給下級(jí)組件中的connect()提供可用的Redux的store對象

是因?yàn)镻rovider里面給下級(jí)組件在context中添加了store對象,所以下級(jí)所有組件都可以拿到store.

export default class Provider extends Component {
  getChildContext() {
    return { store: this.store } // 給下級(jí)組件添加store
  }

  constructor(props, context) {
    super(props, context)
    this.store = props.store
  }

  render() {
    return Children.only(this.props.children) // 渲染children
  }
}
Provider.childContextTypes = {
  store: storeShape.isRequired
}
在源碼中還有一點(diǎn)是關(guān)于hot reload reducers的問題:
let didWarnAboutReceivingStore = false
function warnAboutReceivingStore() {
  if (didWarnAboutReceivingStore) {
    return
  }
  didWarnAboutReceivingStore = true

  warning(
    " does not support changing `store` on the fly. " +
    "It is most likely that you see this error because you updated to " +
    "Redux 2.x and React Redux 2.x which no longer hot reload reducers " +
    "automatically. See https://github.com/reactjs/react-redux/releases/" +
    "tag/v2.0.0 for the migration instructions."
  )
}
if (process.env.NODE_ENV !== "production") {
  Provider.prototype.componentWillReceiveProps = function (nextProps) {
    const { store } = this
    const { store: nextStore } = nextProps

    if (store !== nextStore) {
      warnAboutReceivingStore()
    }
  }
}

好像是React Redux不支持hot reload,根據(jù)里面提供的鏈接,發(fā)現(xiàn)hot reload會(huì)造成錯(cuò)誤,所以在2.x的時(shí)候進(jìn)行了修改,使用replaceReducer的方法來初始化App。具體可以看這里,還有這里。
我并不知道怎么重現(xiàn)這個(gè),我自己在Hot reload下,修改了reducer和action,但是并沒有出現(xiàn)這個(gè)warning...(懵逼臉

connectAdvanced

調(diào)用方法:

connectAdvanced(selectorFactory, options)(MyComponent)

文檔這么介紹的:

把傳入的React組件和Redux store進(jìn)行連接。這個(gè)方法是connect()的基礎(chǔ),但是相比于connect()缺少了合并state, props和dispatch的方法。它不包含一些配置的默認(rèn)值,還有一些便于優(yōu)化的結(jié)果對比。這些所有的事情,都要有調(diào)用者來解決。

這個(gè)方法不會(huì)修改傳入的組件,而是在外面包裹一層,生成一個(gè)新的組件。

這個(gè)方法需要兩個(gè)參數(shù):

selectorFactory 大概的格式是這樣子的selectorFactory(dispatch, factoryOptions)=>selector(state, ownProps)=>props。每次Redux store或者父組件傳入的props發(fā)生改變,selector方法就會(huì)被調(diào)用,重新計(jì)算新的props。最后的結(jié)果props應(yīng)該是一個(gè)plain object,這個(gè)props最后會(huì)被傳給包裹的組件。如果返回的props經(jīng)過對比(===)和上一次的props是一個(gè)對象,那么組件就不會(huì)被re-render。所以如果符合條件的話,selector應(yīng)該返回同一個(gè)對象而不是新的對象(就是說,如果props內(nèi)容沒有發(fā)生改變,那么就不要重新生成一個(gè)新的對象了,直接用之前的對象,這樣可以保證===對比返回true)。
注:在之前的文章中,介紹了selectorFactory.js這個(gè)文件的內(nèi)容。這個(gè)文件里的selectorFactory主要是被connect()方法引入,并傳給connectAdvanced的,算是一個(gè)默認(rèn)的selector。

connectOptions 這個(gè)是非必須參數(shù),中間包含幾個(gè)參數(shù):

getDisplayName(function) 用處不大,主要是用來表示connectAdvanced組件和包含的組件的關(guān)系的。比如默認(rèn)值是name=>"ConnectAdvanced(" + name + ")"。同時(shí)如果用connect()的話,那么這個(gè)參數(shù)會(huì)在connect中被覆蓋成connect(name)。這個(gè)的結(jié)果主要是在selectorFactory中驗(yàn)證拋出warning時(shí)使用,會(huì)被加入到connectOptions一起傳給selectorFactory。

methodName(string) 表示當(dāng)前的名稱。默認(rèn)值是"connectAdvanced",如果使用connect()的話,會(huì)被覆蓋成"connect"。也是被用在拋出warning的時(shí)候使用

renderCountProp(string) 這個(gè)主要是用來做優(yōu)化的時(shí)候使用。如果傳入了這個(gè)string,那么在傳入的props中會(huì)多加一個(gè)prop(key是renderCountProps的值)。這個(gè)值就可以讓開發(fā)獲取這個(gè)組件重新render的次數(shù),開發(fā)可以根據(jù)這個(gè)次數(shù)來減少過多的re-render.

shouldHandleStateChanges(Boolean) 默認(rèn)值是true。這個(gè)值決定了Redux Store State的值發(fā)生改變以后,是否re-render這個(gè)組件。如果值為false,那么只有在componentWillReceiveProps(父組件傳遞的props發(fā)生改變)的時(shí)候才會(huì)re-render。

storeKey(string) 一般不要修改這個(gè)。默認(rèn)值是"store"。這個(gè)值表示在context/props里面store的key值。一般只有在含有多個(gè)store的時(shí)候,才需要用這個(gè)

withRef(Boolean) 默認(rèn)值是false。如果是true的話,父級(jí)可以通過connectAdvanced中的getWrappedInstance方法來獲取組件的ref。

還有一些其他的options, 這些options都會(huì)通過factoryOptions傳給selectorFactory進(jìn)行使用。(如果用的是connect(),那么connect中的options也會(huì)被傳入)

注:withRef中所謂的父級(jí)可以通過getWrappedInstance方法來獲取,可以看看下面的代碼(從stackoverflow拿的):

class MyDialog extends React.Component {
  save() {
    this.refs.content.getWrappedInstance().save();
  }

  render() {
    return (
      
        
      );
   }
}

class Content extends React.Component {
  save() { ... }
}

function mapStateToProps(state) { ... }

module.exports = connect(mapStateToProps, null, null, { withRef: true })(Content);

注:由于我對hot reload的運(yùn)行方法不是很了解。。。所以代碼里的hot reload的地方我就不說了。。。

代碼太長,而且不復(fù)雜,我直接把解釋寫到注釋里:

let hotReloadingVersion = 0
export default function connectAdvanced(
  selectorFactory,
  {
    getDisplayName = name => `ConnectAdvanced(${name})`,
    methodName = "connectAdvanced",
    renderCountProp = undefined,
    shouldHandleStateChanges = true,
    storeKey = "store",
    withRef = false,
    ...connectOptions
  } = {}
) {
  const subscriptionKey = storeKey + "Subscription" // subscription的key
  const version = hotReloadingVersion++ // hot reload version

  const contextTypes = {
    [storeKey]: storeShape, // 從Provider那里獲取的store的type
    [subscriptionKey]: PropTypes.instanceOf(Subscription), // 從上級(jí)獲取的subscription的type
  }
  const childContextTypes = {
    [subscriptionKey]: PropTypes.instanceOf(Subscription) // 傳遞給下級(jí)的subscription的type
  }

  return function wrapWithConnect(WrappedComponent) {
    // 負(fù)責(zé)檢查wrappedComponent是否是function,如果不是拋出異常
    invariant(
      typeof WrappedComponent == "function",
      `You must pass a component to the function returned by ` +
      `connect. Instead received ${WrappedComponent}`
    )

    const wrappedComponentName = WrappedComponent.displayName
      || WrappedComponent.name
      || "Component"

    const displayName = getDisplayName(wrappedComponentName) // 用于異常拋出的名字

    const selectorFactoryOptions = {
      ...connectOptions,
      getDisplayName,
      methodName,
      renderCountProp,
      shouldHandleStateChanges,
      storeKey,
      withRef,
      displayName,
      wrappedComponentName,
      WrappedComponent
    }

    // 如果之前傳入的組件叫做wrappedComponent, 這個(gè)Connect組件應(yīng)該叫wrapComponent,用來包裹wrappedComponent用的
    class Connect extends Component {
      constructor(props, context) {
        super(props, context)

        // 初始化一些信息
        this.version = version
        this.state = {}
        this.renderCount = 0
        this.store = this.props[storeKey] || this.context[storeKey] // 獲取store,有props傳入的是第一優(yōu)先級(jí),context中的是第二優(yōu)先級(jí)。
        this.parentSub = props[subscriptionKey] || context[subscriptionKey] // 獲取context

        this.setWrappedInstance = this.setWrappedInstance.bind(this) // 綁定this值,然而不知道有什么用。。。難道怕別人搶了去?

        // 判斷store是否存在
        invariant(this.store,
          `Could not find "${storeKey}" in either the context or ` +
          `props of "${displayName}". ` +
          `Either wrap the root component in a , ` +
          `or explicitly pass "${storeKey}" as a prop to "${displayName}".`
        )

        this.getState = this.store.getState.bind(this.store); // 定義一個(gè)getState方法獲取store里面的state

        this.initSelector()
        this.initSubscription()
      }

      // 把當(dāng)前的subscription傳遞給下級(jí)組件,下級(jí)組件中的connect就可以把監(jiān)聽綁定到這個(gè)上面
      getChildContext() {
        return { [subscriptionKey]: this.subscription } 
      }

      componentDidMount() {
        if (!shouldHandleStateChanges) return

        this.subscription.trySubscribe()
        this.selector.run(this.props)
        if (this.selector.shouldComponentUpdate) this.forceUpdate()
      }

      componentWillReceiveProps(nextProps) {
        this.selector.run(nextProps)
      }

      // shouldComponentUpdate只有跑過run方法的時(shí)候才會(huì)是true
      // run方法只有在Redux store state或者父級(jí)傳入的props發(fā)生改變的時(shí)候,才會(huì)運(yùn)行
      shouldComponentUpdate() {
        return this.selector.shouldComponentUpdate
      }

      // 把一切都復(fù)原,這樣子可以有助于GC,避免內(nèi)存泄漏
      componentWillUnmount() {
        if (this.subscription) this.subscription.tryUnsubscribe()
        // these are just to guard against extra memory leakage if a parent element doesn"t
        // dereference this instance properly, such as an async callback that never finishes
        this.subscription = null
        this.store = null
        this.parentSub = null
        this.selector.run = () => {}
      }

      // 通過這個(gè)方法,父組件可以獲得wrappedComponent的ref
      getWrappedInstance() {
        invariant(withRef,
          `To access the wrapped instance, you need to specify ` +
          `{ withRef: true } in the options argument of the ${methodName}() call.`
        )
        return this.wrappedInstance
      }

      setWrappedInstance(ref) {
        this.wrappedInstance = ref
      }

      initSelector() {
        const { dispatch } = this.store
        const { getState } = this;
        const sourceSelector = selectorFactory(dispatch, selectorFactoryOptions)

        // 注意這里不會(huì)進(jìn)行任何的setState和forceUpdate,也就是說這里不會(huì)重新渲染
        // 在這里會(huì)記錄上一個(gè)props,并和更新后的props進(jìn)行對比,減少re-render次數(shù)
        // 用shouldComponentUpdate來控制是否需要re-render
        const selector = this.selector = {
          shouldComponentUpdate: true,
          props: sourceSelector(getState(), this.props),
          run: function runComponentSelector(props) {
            try {
              const nextProps = sourceSelector(getState(), props) // 獲取最新的props
              if (selector.error || nextProps !== selector.props) { // 進(jìn)行對比,如果props發(fā)生了改變才改變props對象,并把可渲染flag設(shè)為true
                selector.shouldComponentUpdate = true
                selector.props = nextProps
                selector.error = null
              }
            } catch (error) {
              selector.shouldComponentUpdate = true // 如果有錯(cuò)誤也會(huì)把錯(cuò)誤信息渲染到頁面上
              selector.error = error
            }
          }
        }
      }

      initSubscription() {
        // 如果組件不依據(jù)redux store state進(jìn)行更新,那么根本不需要監(jiān)聽上級(jí)的subscription
        if (shouldHandleStateChanges) {
          // 建立一個(gè)自己的subscription
          const subscription = this.subscription = new Subscription(this.store, this.parentSub)
          const dummyState = {} // 隨便的state, 主要就是用來調(diào)用setState來re-render的

          subscription.onStateChange = function onStateChange() {
            this.selector.run(this.props) // 每次redux state發(fā)生改變都要重新計(jì)算一遍

            if (!this.selector.shouldComponentUpdate) { // 如果當(dāng)前組件的props沒有發(fā)生改變,那么就只通知下級(jí)subscription就好
              subscription.notifyNestedSubs()
            } else {
              // 如果發(fā)生了改變,那么就在更新完以后,再通知下級(jí)
              this.componentDidUpdate = function componentDidUpdate() {
                this.componentDidUpdate = undefined
                subscription.notifyNestedSubs()
              }

              // re-render
              this.setState(dummyState)
            }
          }.bind(this)
        }
      }

      // 判斷是否監(jiān)聽了上級(jí)subscription
      isSubscribed() {
        return Boolean(this.subscription) && this.subscription.isSubscribed()
      }

      // 加入多余的props,注意使用props的影對象進(jìn)行操作,避免把ref添加到selector中,造成內(nèi)存泄漏
      addExtraProps(props) {
        if (!withRef && !renderCountProp) return props

        const withExtras = { ...props }
        if (withRef) withExtras.ref = this.setWrappedInstance
        if (renderCountProp) withExtras[renderCountProp] = this.renderCount++
        return withExtras
      }

      render() {
        const selector = this.selector
        selector.shouldComponentUpdate = false

        if (selector.error) {
          throw selector.error
        } else {
          return createElement(WrappedComponent, this.addExtraProps(selector.props))
        }
      }
    }

    Connect.WrappedComponent = WrappedComponent
    Connect.displayName = displayName
    Connect.childContextTypes = childContextTypes
    Connect.contextTypes = contextTypes
    Connect.propTypes = contextTypes

    if (process.env.NODE_ENV !== "production") {
      Connect.prototype.componentWillUpdate = function componentWillUpdate() {
        // We are hot reloading!
        if (this.version !== version) {
          this.version = version
          this.initSelector()

          if (this.subscription) this.subscription.tryUnsubscribe()
          this.initSubscription()
          if (shouldHandleStateChanges) this.subscription.trySubscribe()
        }
      }
    }

    return hoistStatics(Connect, WrappedComponent)
  }
}

需要注意的:

在組件中, this.store = this.props[storeKey] || this.context[storeKey]; this.parentSub = props[subscriptionKey] || context[subscriptionKey];, 所以props中的store和subscription都是優(yōu)先于context的。所以,如果你決定使用不同的store或者subscription,可以在父組件中傳入這個(gè)值。

connect

connect方法是react-redux最常用的方法。這個(gè)方法其實(shí)是調(diào)用了connectAdvanced方法,只不過和直接調(diào)用不同的是,這里添加了一些參數(shù)的默認(rèn)值。

而且connectAdvanced方法接受的是selectorFactory作為第一個(gè)參數(shù),但是在connect中,分為mapStateToProps, mapDispatchToProps, mergeProps三個(gè)參數(shù),并多了一些pure, areStateEqual, areOwnPropsEqual, areStatePropsEqual, areMergedPropsEqual這些配置。所有的這些多出來的參數(shù)都是用于根據(jù)selectorFactory.js制造一個(gè)簡單的selectorFactory

調(diào)用方法:

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

先看兩個(gè)輔助用的方法:

function match(arg, factories, name) {
  for (let i = factories.length - 1; i >= 0; i--) {
    const result = factories[i](arg)
    if (result) return result
  }

  return (dispatch, options) => {
    throw new Error(`Invalid value of type ${typeof arg} for ${name} argument when connecting component ${options.wrappedComponentName}.`)
  }
}

function strictEqual(a, b) { return a === b }

match之前已經(jīng)在說mapDispatchToProps.js的時(shí)候已經(jīng)提到,這里就不說了。strictEqual就是一個(gè)簡單的絕對相等的封裝。

主題代碼是這樣子的:

export function createConnect({
  connectHOC = connectAdvanced,
  mapStateToPropsFactories = defaultMapStateToPropsFactories,
  mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,
  mergePropsFactories = defaultMergePropsFactories,
  selectorFactory = defaultSelectorFactory
} = {}) {
  return function connect(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps,
    {
      pure = true,
      areStatesEqual = strictEqual,
      areOwnPropsEqual = shallowEqual,
      areStatePropsEqual = shallowEqual,
      areMergedPropsEqual = shallowEqual,
      ...extraOptions
    } = {}
  ) {
    const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, "mapStateToProps")
    const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, "mapDispatchToProps")
    const initMergeProps = match(mergeProps, mergePropsFactories, "mergeProps")

    return connectHOC(selectorFactory, {
      // used in error messages
      methodName: "connect",

       // used to compute Connect"s displayName from the wrapped component"s displayName.
      getDisplayName: name => `Connect(${name})`,

      // if mapStateToProps is falsy, the Connect component doesn"t subscribe to store state changes
      shouldHandleStateChanges: Boolean(mapStateToProps),

      // passed through to selectorFactory
      initMapStateToProps,
      initMapDispatchToProps,
      initMergeProps,
      pure,
      areStatesEqual,
      areOwnPropsEqual,
      areStatePropsEqual,
      areMergedPropsEqual,

      // any extra options args can override defaults of connect or connectAdvanced
      ...extraOptions
    })
  }
}

export default createConnect()
createConnect方法

其中,createConnect方法是一個(gè)factory類的方法,主要是對一些需要的factory進(jìn)行默認(rèn)初始化。

export function createConnect({
  connectHOC = connectAdvanced, // connectAdvanced的方法
  mapStateToPropsFactories = defaultMapStateToPropsFactories, // mapStateToProps.js
  mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories, // mapDispatchToProps.js
  mergePropsFactories = defaultMergePropsFactories, // mergeProps.js
  selectorFactory = defaultSelectorFactory // selectorFactory.js
} = {}) {
  // ...
}

由于這個(gè)方法也是export的,所以其實(shí)由開發(fā)進(jìn)行調(diào)用,可以自定義自己的factory方法,比如你或許可以這么用:

var myConnect = createConnect({
  connectHOC: undefined, // 使用connectAdvanced
  mapStateToPropsFactories: myMapToStatePropsFactories,
  //.....
});

myConnect(mapStateToProps, mapDispatchToProps, options)(myComponnet);

不過這個(gè)方法并沒有在文檔中提到,可能是官方認(rèn)為,你寫這么多factories,還不如用connectAdvanced自己封裝一個(gè)selectorFactory來的方便。

connect方法

在內(nèi)層的connect方法中,除了對幾個(gè)對比方法進(jìn)行初始化,主要是針對factories根據(jù)傳入的參數(shù)進(jìn)行封裝、操作。

function connect(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps,
    {
      pure = true,
      areStatesEqual = strictEqual,
      areOwnPropsEqual = shallowEqual,
      areStatePropsEqual = shallowEqual,
      areMergedPropsEqual = shallowEqual,
      ...extraOptions
    } = {}
  ) {
  // .......
}

這里的pure參數(shù)和equal參數(shù)都在前兩篇中有詳細(xì)的描述(connect工具類1, connect工具類2),可以在那里看看。

提一點(diǎn),項(xiàng)目中可以通過根據(jù)不同的情況優(yōu)化...Equal的四個(gè)方法來優(yōu)化項(xiàng)目,減少必不要的重新渲染,因?yàn)槿绻@個(gè)*Equal方法驗(yàn)證通過,就不會(huì)返回新的props對象,而是用原來儲(chǔ)存的props對象(對某些層級(jí)比較深的情況來說,即使第一層內(nèi)容相同,shallowEqual也會(huì)返回false,比如shallowEqual({a: {}}, {a: {}})),那么在connectAdvanced中就不會(huì)重新渲染。

connect內(nèi)部實(shí)現(xiàn)
const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, "mapStateToProps")
    const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, "mapDispatchToProps")
    const initMergeProps = match(mergeProps, mergePropsFactories, "mergeProps")

    return connectHOC(selectorFactory, {
      methodName: "connect", // 覆蓋connectAdvanced中的methodName, 用于錯(cuò)誤信息顯示

      getDisplayName: name => `Connect(${name})`, // 覆蓋connectAdvanced中的getDisplayName, 用于錯(cuò)誤信息顯示

      shouldHandleStateChanges: Boolean(mapStateToProps), // 如果mapStateToProps沒有傳,那么組件就不需要監(jiān)聽redux store

      // passed through to selectorFactory
      initMapStateToProps,
      initMapDispatchToProps,
      initMergeProps,
      pure,
      areStatesEqual,
      areOwnPropsEqual,
      areStatePropsEqual,
      areMergedPropsEqual,

      // any extra options args can override defaults of connect or connectAdvanced
      ...extraOptions
    })

中間需要提一點(diǎn),就是shouldHandleStateChanges的這個(gè)屬性。根據(jù)文檔中對mapStateToProps的介紹,有一句話是:

mapStateToProps 如果這個(gè)沒有傳這個(gè)參數(shù),那么組件就不會(huì)監(jiān)聽Redux store.

其實(shí)原因很簡單,由于connect中只有mapStateToProps(state, [ownProps])是根據(jù)redux store state的改變進(jìn)行改變的,而像mapDispatchToProps(dispatch, [ownProps])mergeProps(stateProps, dispatchProps, ownProps)都和redux store無關(guān),所以如果mapStateToProps沒有傳的話,就不需要去監(jiān)聽redux store。

一點(diǎn)總結(jié): 可以怎么去做性能優(yōu)化?

除了最最基礎(chǔ)的shouldComponentUpdate之外,針對Redux React,我們可以通過優(yōu)化areStatesEqual, areOwnPropsEqual, areStatePropsEqual, areMergedPropsEqual四個(gè)方法,來確保特殊情況下,props的對比更精確。

pure盡量使用默認(rèn)的true,只有在內(nèi)部的渲染會(huì)根據(jù)除了redux store和父組件傳入的props之外的狀態(tài)進(jìn)行改變,才會(huì)使用false。但是false會(huì)造成忽略上面的對比,每次改變都進(jìn)行重新渲染

mapStateToProps, mapDispatchToProps如果不需要ownProps參數(shù),就不要寫到function定義中,減少方法的調(diào)用次數(shù)。

如果mapStateToProps不需要的話,就不傳或者undefined,不要傳noop的function,因?yàn)閚oop方法也會(huì)讓shouldHandleStateChanges為true,平白讓connect多了一個(gè)監(jiān)聽方法。

自定義store

之前有提到,react redux是接受自定義store的。也就是說你可以從父組件傳入一個(gè)store給connect組件,connect組件就會(huì)優(yōu)先使用這個(gè)store。但是store必須有一定的格式,比如里面需要有一個(gè)getState方法來獲取state。

加個(gè)參數(shù)來控制是否渲染

在connectAdvanced里面,他們使用了selector.shouldComponentUpdate來控制是否需要渲染,然后在React的shouldComponentUpdate里面返回這個(gè)屬性。這個(gè)方法的優(yōu)點(diǎn)就是,就像一個(gè)開關(guān),當(dāng)需要渲染的時(shí)候再打開,不需要渲染或者渲染后關(guān)閉開關(guān)。便于控制,同時(shí)某些不需要渲染的setState,也不會(huì)造成渲染。

一個(gè)獲取子組件中的component ref的小方法

在看getWrappedInstance方法的時(shí)候,在github上面看到原作者的一個(gè)小方法,可以用來獲取子組件中的component。
代碼很清晰,只是有的時(shí)候想不到,直接上代碼:

class MyComponent extends Component {
  render() {
    return (
      
); } } class ParentComponent extends Component { componentDidMount() { this.input.focus(); } render() { return ( this.input = input} /> ) } }

用這種方法,就可以把input的ref直接傳遞給parentComponent中,在parentComponent中就可以直接對Input進(jìn)行操作。這個(gè)方法對用connect包裹后的組件同樣有效。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/81121.html

相關(guān)文章

  • 深入redux技術(shù)棧

    摘要:另外,內(nèi)置的函數(shù)在經(jīng)過一系列校驗(yàn)后,觸發(fā),之后被更改,之后依次調(diào)用監(jiān)聽,完成整個(gè)狀態(tài)樹的更新。總而言之,遵守這套規(guī)范并不是強(qiáng)制性的,但是項(xiàng)目一旦稍微復(fù)雜一些,這樣做的好處就可以充分彰顯出來。 這一篇是接上一篇react進(jìn)階漫談的第二篇,這一篇主要分析redux的思想和應(yīng)用,同樣參考了網(wǎng)絡(luò)上的大量資料,但代碼同樣都是自己嘗試實(shí)踐所得,在這里分享出來,僅供一起學(xué)習(xí)(上一篇地址:個(gè)人博客/s...

    imingyu 評論0 收藏0
  • 深入redux技術(shù)棧

    摘要:另外,內(nèi)置的函數(shù)在經(jīng)過一系列校驗(yàn)后,觸發(fā),之后被更改,之后依次調(diào)用監(jiān)聽,完成整個(gè)狀態(tài)樹的更新。總而言之,遵守這套規(guī)范并不是強(qiáng)制性的,但是項(xiàng)目一旦稍微復(fù)雜一些,這樣做的好處就可以充分彰顯出來。 這一篇是接上一篇react進(jìn)階漫談的第二篇,這一篇主要分析redux的思想和應(yīng)用,同樣參考了網(wǎng)絡(luò)上的大量資料,但代碼同樣都是自己嘗試實(shí)踐所得,在這里分享出來,僅供一起學(xué)習(xí)(上一篇地址:個(gè)人博客/s...

    VPointer 評論0 收藏0
  • React 入門實(shí)踐

    摘要:更多相關(guān)介紹請看這特點(diǎn)僅僅只是虛擬最大限度減少與的交互類似于使用操作單向數(shù)據(jù)流很大程度減少了重復(fù)代碼的使用組件化可組合一個(gè)組件易于和其它組件一起使用,或者嵌套在另一個(gè)組件內(nèi)部。在使用后,就變得很容易維護(hù),而且數(shù)據(jù)流非常清晰,容易解決遇到的。 歡迎移步我的博客閱讀:《React 入門實(shí)踐》 在寫這篇文章之前,我已經(jīng)接觸 React 有大半年了。在初步學(xué)習(xí) React 之后就正式應(yīng)用到項(xiàng)...

    shenhualong 評論0 收藏0
  • React Redux: 文檔源碼 - Utils

    注:這篇文章只是講解React Redux這一層,并不包含Redux部分。Redux有計(jì)劃去學(xué)習(xí),等以后學(xué)習(xí)了Redux源碼以后再做分析注:代碼基于現(xiàn)在(2016.12.29)React Redux的最新版本(5.0.1) Utils篇 這一小節(jié)里面先把基礎(chǔ)的Utils代碼過一遍,以后看核心代碼的時(shí)候方便一點(diǎn)。由于是Utils不涉及文檔,所以沒有文檔方面的展示 shallowEqual.js 從名...

    VishKozus 評論0 收藏0
  • redux的一些筆記

    摘要:不只為組件提供中的數(shù)據(jù)及擴(kuò)展方法,它還為定義的組件添加了一系列事件操作,這些事件的核心點(diǎn)就是,然后可以在自己定義的組件內(nèi)獲得。行為功能是對目的功能和有用行為的一種抽象。下一個(gè)中間件函數(shù)通常由名為的變量來表示。 redux 這個(gè)是好久之前寫的,一直忘記粘過來,里面有一些是寫作格式是我自己定義的,所以和segmentfault的markdown語法有出入,圖片也不能加載,所以原文效果可以在...

    el09xccxy 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<