React-Redux (1): @connect
0 缘起
之前有次面试被问起 connect
方法是如何把 store 的 state 传递到 Component 的,当时没有回答到点子上,拖到现在终于强迫自己坐下来搞清楚这个事情。
1 API
先看看官方文档关于 connect() 方法的说明:Connect · React Redux | 中文版
大概翻译一下:connect()
方法把一个 React 组件绑定到 Redux store 上。
方法返回一个新组件,新组件包含所有传入组件需要从 store 上获取的数据或者向 store 触发的方法
connect 不会修改组件,而是返回一个新的绑定组件包裹原组件。
1 | function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?) |
更多内容请参考官方文档。
2 实现
那么 connect
底层是如何实现的呢?
通过源码看一下:
源代码位于:github.com/reduxjs/react-redux/connect/connect.js
这里对 connect
的参数进行了一个默认值处理,没有涉及核心功能,继续调用了 connectAdvanced
:
github.com/reduxjs/react-redux/components/connectAdvanced.js
方法很长,前面都是对一些过期选项的警告和一些值的处理。核心代码位于 ConnectFunction
内部
第 171 行处 获取到当前使用的 context
1 | const ContextToUse = useMemo(() => { |
第 385 行处,执行了具体的 connect
过程
1 | // Now that all that's done, we can finally try to actually render the child component. |
可以看到,其实底层就是使用 Context.Provider 向被绑定的组件注入需要的属性(包括 mapStateToProps 和 dispatch相关方法)。
3 踩坑
最初看代码的时候搞不清楚 ReactReduxContext
这个 Context 是如何跟外层的 store 关联起来的,因为漏掉了最外层的 Provider
https://react-redux.js.org/api/provider。
react-redux 提供两种引用方式:在最外层使用 react-redux 提供的 Provider 组件包裹 或者 每次 connect 时候都要传入 context 实例的方式,以此保证唯一数据源。
4 其他
整个实现过程非常巧妙,包括一些默认值的处理,一些方法重载的实现,非常值得参考。