You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
如果当前组件不是根组件,说明已经有组件注册到了 redux store 了,那在子组件中可以拿到通过context传递的subscription(由于是父组件的监听类又称为parentSub),那么当前子组件的回调会注册到parentSub上。并且会新建一个Subscription实例,在context上继续传递,那么当前组件的子组件回调会注册到当前组件的Subscription实例上
当state变化了,根组件注册到 redux store 的回调会更新根组件,根组件会手动更新子组件的回调,子组件的回调执行更新子组件,子组件会执行subscription上注册的回调,触发孙子组件更新...这样子就实现了一层一层的组件更新,保证了父→子的更新顺序
阅读本文前,请先阅读前文数据流前篇
回顾以及引入问题
在之前的设计中,我们使用 useReducer 获得了一个强制更新函数(
forceComponentUpdateDispatch
),然后在store.subcribe
回调函数中执行上述代码已经实现了 store 中数据改变时,对应使用 connect 包裹的组件能够获得对应数据,但是存在一个更新顺序的问题。
在前文中,我们提及到 React 是单向数据流,props 都是父组件传递给子组件的。一旦我们引入了 redux 后,假设父子组件都会引用了同一个变量
count
,子组件根本不会从父组件拿该参数,而是直接从 redux 中读取,这使得 React 的原本父→子的单向数据流被打破了。再说到更新问题,在 React 中,如果一个共同变量变化了,那必然是父组件先更新,再把数据传给子组件做更新。但是 redux 里,数据变成 redux→父,redux→子,父子组件完全根据 redux 的数据做独立更新,不能完全保证父组件先更新,子组件再更新。react-redux 为了保证更新顺序引入了一个监听者类
Subscription
Subscription类
Subscription
需要做什么?线上代码state
回调直接注册到 redux store;同时创建一个Subscription
实例(subscription
)并且通过context
传递给子级context
传递的subscription
(由于是父组件的监听类又称为parentSub
),那么当前子组件的回调会注册到parentSub
上。并且会新建一个Subscription
实例,在context
上继续传递,那么当前组件的子组件回调会注册到当前组件的Subscription
实例上state
变化了,根组件注册到 redux store 的回调会更新根组件,根组件会手动更新子组件的回调,子组件的回调执行更新子组件,子组件会执行subscription
上注册的回调,触发孙子组件更新...这样子就实现了一层一层的组件更新,保证了父→子的更新顺序Subscription源码
对应改造
Provider
在我们使用 redux 的时候,
Provider
始终是我们的根组件,所以需要给Provider
创建一个Subscription
实例再通过context
传递下去,线上代码Provider源码
Connect
在之前的版本中,connect 是直接注册到 store 上,那现在就应该注册在父级的
subscription
上,在自己更新完成之后,再去通知自己的子级做更新。还有就是我们需要重写
context
中的subscription
,因为当前组件拿到的subscription
是属于它父级的,而当前组件的子级需要的subscription
是当前组件创建的,我们需要重写context
中的subscription
,所以我们的connect
返回的组件需要用Context.Provider
包裹一下。线上代码connect源码
总结
在本文中,提出了上一篇文章中
connect
实现的问题,由于 Redux 的引入使得 React 原本的数据流遭遇破坏。通过引入Subscription
类实现发布订阅模式,来保证父父→子的一个更新顺序。数据发生改变时,从根组件开始通知自己的子组件,子组件通知其子组件,这样来保证更新顺序。The text was updated successfully, but these errors were encountered: