前言
在 十分钟学会 react-redux 一文中详细讲解了 react-redux 的使用。
在 从零到一实现 Redux 中,实现了关于 redux 的核心代码。
下面我们按照上一篇的节奏,继续实现一下 react-redux 的核心代码。
本文已收录在 Github: https://github.com/beichensky/Blog 中,欢迎 Star!
核心 API
包含以下核心 API
Provider: 上下文组件
connect: 带参的高阶函数
useSelector: 获取需要的 state 数据
useDispatch: 获取 dispatch
一、Provider
全局只有一个 store 对象,需要在多层级组件中传递 store,
并且 store 中的 state 发生变化,组件需要相应的做出更新。
所以这里我们使用 Context 进行数据传递
import React, { useContext, useEffect, useReducer } from "react";
import { bindActionCreators } from "./redux";
const StoreContext = React.createContext();
/**
* Provider 组件,用来传递 Context 中数据,进行跨层级组件通信
*/
const Provider = ({ store, children }) => (
// 将 store 作为 value 传递下去
<StoreContext.Provider value={store}>{children}</StoreContext.Provider>
);
export { Provider, connect, useDispatch, useSelector };
二、connect 高阶函数
-
订阅监听事件,state 发生变化,强制更新组件
-
将 stateProps、dispatchProps、mergeProps 合并到组件的 props 中
-
API:connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options])
connect 的用法相对复杂一些,接受四个参数(我们这里暂时不管第四个参数),返回的是一个高阶组件。用来连接当前组件和 Redux store。
1. mapStateToProps
mapStateToProps:函数类型,接受两个参数: state 和 ownProps(当前组件的 props,不建议使用,会导致重渲染,损耗性能),必须返回一个纯对象,这个对象会与组件的 props 合并
(state[, ownProps]) => ({ count: state.count, todoList: state.todos })
2. mapDispatchToProps
mapDispatchToProps:object | 函数
-
不传递这个参数时,dispatch 会默认挂载到组件的的 props 中
-
传递 object 类型时,会把 object 中的属性值使用 dispatch 包装后,与组件的 props 合并
-
传递函数类型时,接收两个参数:dispatch 和 ownProps(当前组件的 props,不建议使用,会导致重渲染,损耗性能),必须返回一个纯对象,这个对象会和组件的 props 合并
3. mergeProps
mergeProps:(很少使用) 函数类型。如果指定了这个参数,mapStateToProps()与 mapDispatchToProps()的执行结果和组件自身的 props 将传入到这个回调函数中。该回调函数返回的对象将作为 props 传递到被包装的组件中。你也许可以用这个回调函数,根据组件的 props 来筛选部分的 state 数据,或者把 props 中的某个特定变量与 ActionCreator 绑定在一起。如果你省略这个参数,默认情况下组件的 props 返回 Object.assign({}, ownProps, stateProps, dispatchProps) 的结果
mergeProps(stateProps, dispatchProps, ownProps): props
connect
/**
* connect 函数,源码中包含四个参数,我们这里只用到这些,所以就暂时只实现了前三个参数
*
* @param {*} mapStateToProps 将 state 合并到组件的 props 中的函数
* @param {*} mapDispatchToProps 将 actionCreator 合并到组件的 props 中的函数
* @param {*} mergeProps 自定义属性合并到组件的 props
*/
const connect = (
mapStateToProps,
mapDispatchToProps,
mergeProps
) => WrapperComponent => {
return props => {
const { getState, dispatch, subscribe } = useContext(StoreContext);
const [, forceUpdate] = useReducer(x => x + 1, []);
// 执行 mapStateToProps,获取用户需要的 state 数据
const stateProps = mapStateToProps(getState());
// 默认将 dispatch 挂载到 props 上
let dispatchProps = { dispatch };
// 判断 mapDispatchToProps 是函数还是对象,函数的话,执行获取返回的对象
if (typeof mapDispatchToProps === "function") {
dispatchProps = mapDispatchToProps(dispatch);
} else if (mapDispatchToProps === "object") {
// 对象的话,直接将对象中的 actionCreator 使用 dispatch 进行包装
dispatchProps = bindActionCreators(mapDispatchToProps, dispatch);
}
mergeProps = mergeProps(stateProps, dispatchProps, props);
useEffect(() => {
// 添加事件订阅,state 发生变化时会触发,更新组件
const unsubscribe = subscribe(() => forceUpdate());
return () => {
unsubscribe();
};
}, [subscribe]);
return (
<WrapperComponent
{...props}
{...stateProps}
{...dispatchProps}
{...mergeProps}
/>
);
};
};
三、useDispatch 获取 dispatch
useDispatch
/**
* 获取 store 对象
*/
const useStore = () => {
const store = useContext(StoreContext);
return store;
};
/**
* 获取 store 中 dispatch
*/
const useDispatch = () => {
const store = useStore();
return store.dispatch;
};
四、useSelector 获取需要的 state 值
/**
* useSelector 从 store 中获取当前组件所需要的 state
*
* @param {(state) => props} selector 用户传入的函数,接收 store 当前的 state,返回一个组织好的数据对象
*/
const useSelector = selector => {
const [, forceUpdate] = useReducer(x => x + 1, []);
const { subscribe, getState } = useStore();
useEffect(() => {
// 添加事件订阅,state 发生变化时会触发,更新组件
const unsubscribe = subscribe(() => forceUpdate());
return () => {
unsubscribe();
};
}, [subscribe]);
return selector(getState());
};
系列文章
写在后面
至此, react-redux 的核心功能基本已经实现,不过有很多细节和参数的兼容都没有进行处理,有兴趣的朋友可以参照源码完善。
源码地址
如果有写的不对或不严谨的地方,欢迎大家能提出宝贵的意见,十分感谢。
如果喜欢或者有所帮助,欢迎 Star,对作者也是一种鼓励和支持。
前言
在 十分钟学会 react-redux 一文中详细讲解了
react-redux的使用。在 从零到一实现 Redux 中,实现了关于 redux 的核心代码。
下面我们按照上一篇的节奏,继续实现一下
react-redux的核心代码。核心 API
包含以下核心
APIProvider: 上下文组件connect: 带参的高阶函数useSelector: 获取需要的state数据useDispatch: 获取dispatch一、Provider
全局只有一个 store 对象,需要在多层级组件中传递
store,并且 store 中的 state 发生变化,组件需要相应的做出更新。
所以这里我们使用
Context进行数据传递二、connect 高阶函数
订阅监听事件,
state发生变化,强制更新组件将
stateProps、dispatchProps、mergeProps合并到组件的props中API:connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options])connect的用法相对复杂一些,接受四个参数(我们这里暂时不管第四个参数),返回的是一个高阶组件。用来连接当前组件和Redux store。1. mapStateToProps
mapStateToProps:函数类型,接受两个参数:state和ownProps(当前组件的props,不建议使用,会导致重渲染,损耗性能),必须返回一个纯对象,这个对象会与组件的props合并(state[, ownProps]) => ({ count: state.count, todoList: state.todos })2. mapDispatchToProps
mapDispatchToProps:object | 函数不传递这个参数时,
dispatch会默认挂载到组件的的props中传递
object类型时,会把object中的属性值使用dispatch包装后,与组件的props合并对象的属性值都必须是
ActionCreatordispatch不会再挂载到组件的props中传递函数类型时,接收两个参数:
dispatch和ownProps(当前组件的props,不建议使用,会导致重渲染,损耗性能),必须返回一个纯对象,这个对象会和组件的props合并3. mergeProps
mergeProps:(很少使用) 函数类型。如果指定了这个参数,mapStateToProps()与mapDispatchToProps()的执行结果和组件自身的props将传入到这个回调函数中。该回调函数返回的对象将作为props传递到被包装的组件中。你也许可以用这个回调函数,根据组件的props来筛选部分的state数据,或者把props中的某个特定变量与ActionCreator绑定在一起。如果你省略这个参数,默认情况下组件的props返回Object.assign({}, ownProps, stateProps, dispatchProps)的结果mergeProps(stateProps, dispatchProps, ownProps): propsconnect三、useDispatch 获取 dispatch
useDispatch四、useSelector 获取需要的 state 值
订阅事件监听,
state发生变化,强制更新组件接受一个函数作为参数,函数的返回值作为
useSelector的返回值传递出去系列文章
轻松掌握 Redux 核心用法
十分钟学会 react-redux
从零到一实现 Redux
从零到一实现 react-redux
写在后面
至此,
react-redux的核心功能基本已经实现,不过有很多细节和参数的兼容都没有进行处理,有兴趣的朋友可以参照源码完善。源码地址
如果有写的不对或不严谨的地方,欢迎大家能提出宝贵的意见,十分感谢。
如果喜欢或者有所帮助,欢迎 Star,对作者也是一种鼓励和支持。