前言
在上文手写redux中,我们实现了数据响应式流向,但是在react中使用还是过于繁琐了,比如数据监听,卸载,多dispatch调用。社区中有人为了解决这个问题就写了基于redux数据源的新插件react-redux,这次就来实现该代码,更加深入了解react-redux的诞生原因,及实现原理。
react-redux
react-redux中的两大核心就是connect,Provider。
- 使用createContext来进行跨层级数据传递(store)
- 使用connect返回新组件(高阶组件思想)
Provider
创建Context进行跨组件数据传递
// 创建上下文(Context),传递store
const Context = React.createContext();
// 通过Provider传递value(接收到的store)
export function Provider({ store, children }) {
return <Context.Provider value={store}>{children}</Context.Provider>
}
// 使用页
import { Provider } from "./react-redux";
import store from './store';
import Index from "./pages/index";
// 传递store数据
function App() {
return (
<Provider store={store}>
<div className="App">
<Index/>
</div>
</Provider>
);
}
connect
实现操作流程简化的核心函数,设计思想是通过创建一个新的函数组件,为它赋予增强后的props属性,及各类操作。 用户使用时,就可专注于action操作,而不需每次操作时都使用dispatch。还实现了自动数据监听,自动卸载等。
// connect,是一个高阶组件(参数是组件,返回值是组件)
export function connect(mapStateToProps, mapDispatchToProps) {
// 第一个返回函数接收一个组件
return function(WrappedComponent) {
// 第二个返回函数接收props, 这里的返回值其实就是 WrappedIndex(是一个函数式组件,可接收props进行其他逻辑操作)
return function(props) {
// console.log("connect props", props);
const store = useContext(Context); // 拿到接收的数据(Provider传递的)
const { getState, dispatch, subscribe } = store;
const stateProps = mapStateToProps(getState()); // 返回store中的state(初始化)
// 合并dispatch选项,让用户可以直接调用dispatch传递action,进行操作。
let dispatchProps = { };
if (typeof mapDispatchToProps === "object") { // 是对象则合并,并保存传递的函数
dispatchProps = bindActionCreators(mapDispatchToProps, dispatch);
}
if (typeof mapDispatchToProps === "function") { // 是函数则直接调用并传入dispatch给用户使用
dispatchProps = mapDispatchToProps(dispatch);
}
// 更新
const forceUpdate = useForceUpdate();
// 初始化监听和卸载时取消监听
useLayoutEffect(() => {
const unsubscribe = subscribe(() => {
forceUpdate();
})
return () => {
unsubscribe && unsubscribe()
}
}, [store])
// 返回第一个函数接收的组件,并给该组件 添加props(接收到的props,mapstateProps,dispatchProps)。
// 这样就将组件中需要的数据,操作等参数通过props的方式传递下去了。并且帮助该组件自动完成了数据监听(更新组件),组件销毁时(卸载监听)。
return <WrappedComponent {...props} {...stateProps} {...dispatchProps} dispatch={dispatch}/>
}
}
}
useDispatch、useForceUpdate、bindActionCreators、bindActionCreator
一些辅助函数
// 使用hook返回dispatch
export function useDispatch() {
const store = useContext(Context);
return store.dispatch;
}
// 使用函数hooks创建一个自增的更新函数。当state变化时 就能触发更新
function useForceUpdate() {
const [, setState] = useState(0);
const update = useCallback(() => {
setState(prev => prev + 1)
}, [])
return update;
}
export function bindActionCreators(creators, dispatch) {
const obj = {};
for (const key in creators) {
obj[key] = bindActionCreator(creators[key], dispatch);
}
return obj;
}
function bindActionCreator(creator, dispatch) {
// 这里的args,是触发这个函数的宿主元素(input => onChange, div => onClick);
// 该函数绑定在谁身上触发,或者手动调用触发,接收的宿主或传递的参数
return (...args) => dispatch(creator(...args))
}
结语
至此我们便完成了react-redux的大致实现,写完这个代码后我对它理解更深了,核心思想就是高阶组件+Context。短短几十行代码,但是实现的东西很巧妙。github代码地址