前言
前段时间,由于需要封装一个类 v-model 的 React 组件,这个组件需要传 field 字段,此字段需要传入取值的字符串路径。此时,当在 input 中输入时,会同步修改数据源中 name;当修改数据源中 name 值时,也会同步到 input 组件。由于 div 内可能存在组件嵌套,所以就需要使用 Context。(PS:由于抽出的组件,既想让其支持新版 Context,也想让其支持旧版 Context,故作此研究。)
如何兼容新、旧 Context
对于跨级组件传递数据来说,不仅仅可通过 Context 来实现,还可以通过事件订阅来实现。
mini-create-react-context 内部就是使用事件订阅模式模拟 createContext,可能大部分人对这个三方包很陌生,但是大家对 react-router 绝对不会陌生,react-router 内部源码就是使用这个三方包来创建 Context。
mini-create-react-context 内部会在不存在新版 Context 时,向外界暴露 createReactContext 方法,此方法接收 defaultValue,并返回 Provider 和 Consumer 两个组件。
我们先看 Provider 组件,组件内部会通过旧版 Context 给后代传入一个事件订阅器,每当组件的 props 发生变化,都会通过事件订阅器推送事件。
Consumer 组件在 componentDidMount 中通过传入的事件订阅器订阅事件,如果接收到事件,则通过 onUpdate 方法来执行 setState,更新组件。
说到这里,不得不提下旧版
Context 的问题,旧版 Context 如果在数据传输的中间组件 SCU 返回 false,则以后的组件都不会收到更新后的值,也不会触发 reRender。上面我们已经通过事件订阅解决了不会更新的问题,但是还未解决无法获取新值的问题。
mini-create-react-context 在 Consumer 组件内部,通过事件订阅器上 get 方法来获取新值,在Provider 组件内部又通过 set 方法去设置新值,此处恰到好处的利用了闭包解决了新旧值的传递问题。