一、引言

之前学习了Redux,而后发现有Redux的中央简直都少不了react-redux这个库,它能够说是建设了React组件和Redux之间的桥梁。所以我顺便学习了react-redux,觉得很有必要记录一下。

二、为什么须要应用react-redux

如果不必react-redux的话,咱们想在React组件中应用Redux,就不得不引入store,应用store.dispatch(action)去分派action,间接地扭转状态。乍一看,这样没什么问题啊,是的,如果只是一个组件的话这样的确没什么问题。然而,试想,如果该组件的子组件也想用名为xxx的state的话,岂不是又得引入store,而后又是像父组件那样一套流程下来,这样的确失效,然而显得代码十分的臃肿,可维护性很差,因为做了很多反复的工作。然而如果咱们引入一个容器组件,这个组件能够应用props的形式将state和dispatch传递给子组件,这样就省去了很多反复的工作。这时,react-redux库就发挥作用了,建设起React和store的桥梁,能够将store和dispatch映射给props,这样React的组件就能够通过props将state和dispatch向下传递;或者能够应用Provider提供一个context,将store无限度向下传递给子孙组件。

三、react-redux做了什么

先说一下react-redux做了什么:

  • 提供Subscrption类,实现订阅更新的逻辑
  • 提供Provider,将store传入Provider,便于上层组件从context或者props中获取store;并订阅store的变动,便于在store变动的时候执行被订阅到react-redux内的更新函数
  • 提供selector,负责将获取store中的state和dispacth一些action的函数(或者间接就是dispatch)或者组件本人的props,从中抉择出组件须要的值,作为selector的返回值
  • 提供connect高阶组件,次要做了两件事:

    • 执行selector,获取到要注入到组件中的值,将它们注入到组件的props
    • 订阅props的变动,负责在props变动的时候更新组件

四、react-redux是怎么做到的

当我理解到react-redux的大抵性能之后,我脑海里立马产生了三个疑难,别离是:

  • Provider是如何将store放入context中的?
  • 如何将store中的state和dispatch(或调用dispatch的函数)注入组件中的props的?
  • React-Redux如何做到当store变动,被connect的组件也会更新的?(如何监测store的变动?)

五、解决以上提出的问题

1.Provider是怎么把store放入context中的?

先来看Provider.js的源码:

function Provider({ store, context, children }) {  const contextValue = useMemo(() => {    //申明一个Subscription实例。订阅,监听state变动来执行listener,都由实例来实现    const subscription = new Subscription(store)    //绑定监听,当state变动时,告诉订阅者更新页面,实际上也就是在connect过程中被订阅到react-redux的subscription对象上的更新函数    subscription.onStateChange = subscription.notifyNestedSubs    return {      store,      subscription    }  }, [store])  //获取以后的store的state,作为上一次的state,将会在组件挂载结束后,  //与store新的state比拟,不统一的话更新Provider组件  const previousState = useMemo(() => store.getState(), [store])  useEffect(() => {    //这会在组件渲染之后执行,所以这个时候contextValue曾经返回    //在组件挂载结束后,订阅更新。    const { subscription } = contextValue       //contextValue = { store, subscription }    //这里先了解为最开始的时候须要订阅更新函数,便于在状态变动的时候执行更新函数,相当于是注册了一个监听,在监听state的变动。    subscription.trySubscribe()    //如果前后的store中的state有变动,那么就去更新Provider组件    if (previousState !== store.getState()) {      subscription.notifyNestedSubs()    }    return () => {      subscription.tryUnsubscribe()      subscription.onStateChange = null    }  }, [contextValue, previousState])  const Context = context || ReactReduxContext  return <Context.Provider value={contextValue}>{children}</Context.Provider>}if (process.env.NODE_ENV !== 'production') {  //propTypes仅在开发模式下进行查看  Provider.propTypes = {    store: PropTypes.shape({      subscribe: PropTypes.func.isRequired,      dispatch: PropTypes.func.isRequired,      getState: PropTypes.func.isRequired    }),    context: PropTypes.object,    children: PropTypes.any  }}export default Provider

所以联合代码看这个问题:Provider是怎么把store放入context中的,很好了解。
Provider最次要的性能是从props中获取咱们传入的store,并将store作为context的其中一个值,向上层组件下发

然而,一旦store变动,Provider要有所反馈,以此保障将始终将最新的store放入context中。所以这里要用订阅来实现更新。天然引出Subscription类,通过该类的实例,将onStateChange监听到一个可更新UI的事件this.notifySubscribers上:

subscription.onStateChange = this.notifySubscribers

组件挂载实现后,去订阅更新,至于这里订阅的是什么,要看Subscription的实现。这里先给出论断:实质上订阅的是onStateChange,实现订阅的函数是:Subscription类之内的trySubscribe。

this.state.subscription.trySubscribe()

再接着,如果前后的state不一样,那么就去告诉订阅者更新,onStateChange就会执行,Provider组件就会执行上层组件订阅到react-redux的更新函数。当Provider更新实现(componentDidUpdate),会去比拟一下前后的store是否雷同,如果不同,那么用新的store作为context的值,并且勾销订阅,从新订阅一个新的Subscription实例。保障用的数据都是最新的。

//如果前后的store中的state有变动,那么就去更新Provider组件if (previousState !== store.getState()) {  subscription.notifyNestedSubs()}return () => {  subscription.tryUnsubscribe()  subscription.onStateChange = null}

//未实现...