实现一个react-redux的connect函数
我们在使用redux的时候,经常会使用到react-redux库里面的connect,他接受两个参数,返回值也是一个函数,并接收一个组件,实现组件与redux的结合。他的实现原理很简单,这篇文章将实现一个自定义connect函数,并具备react-redux的connect的功能。
- 首先需要定义一个connect函数,并接收两个参数:mapStateToProps与mapActionToProps。
- mapStateToProps可以理解为需要从redux中订阅哪些数据。
- mapActionToProps可以理解为需要如何修改redux中的数据。
- 在组件的构造函数construct中使用matStateToProps函数将需要的数据从redux获取,并为组件提供一个初始化状态。
- 在组件挂载完毕后,订阅redux中的数据,当redux中的数据被修改时,会触发subscribe函数,并执行组件的setState方法,完成组件状态的更新以及页面的重新渲染。
- 组件的render部分,需要将mapStateToProps获取到的redux状态,mapActionToProps处理后的修改redux的store的方法,以及其他参数,传递给组件。
- 最后在组件的销毁时,取消订阅redux,防止内存泄露。
import { StoreContext } from './context';
// 定义一个connect函数,并接收两个参数
export const connect = function (mapStateToProps, mapActionToProps) {
// 返回值是一个函数,接收一个组件,并返回一个组件
return function (Cpn) {
class WraperCpn extends PureComponent {
static contextType = storeContext;
constructor(props, context) {
super(props, context);
// 在组件创建的时候,初始化组件状态数据
this.storeState = mapStateToProps(context);
}
componentDidMount() {
// 在组件挂载后,订阅redux中的数据
this.unsubscribe = this.context.subscribe(() => {
this.setState({
storeState: mapStateToProps(this.context)
})
})
}
componentWillUnmount() {
// 在组件销毁的时候,取消组件订阅的redux
this.unsubscribe();
}
render() {
return <Cpn
{...this.props}
{...mapStateToProps(this.context)}
{...mapActionToProps(this.context.dispatch)}></Cpn>
}
}
return WraperCpn;
}
}
mapStateToProps 与 mapDispatchToProps
这俩函数通常是这种格式,mapStateToProps接收redux的store,返回组件所需的状态数据。mapDispatchToProps通常接收redux的dispatch方法,执行状态变更的相关操作。
const mapStateToProps = state => ({
counter: state.counter
})
const mapDispatchToProps = dispatch => ({
increment() {
dispatch(incAction());
},
addNumber(num) {
dispatch(addAction(num));
}
})
为了使该connect更具有拓展性,在自定义connect中,我们导入了一个context.js,他提供了一个context,是为了在外部传递store数据给connect。到这里就实现了react-redux的connect函数。
context.js
import React from 'react';
const StoreContext = React.createContext();
export {
StoreContext
}
通过StoreContext.Provider就可以将store传递给使用了自定义connect函数的子组件
import React from 'react';
import ReactDOM from 'react-dom';
import store from './store';
import { StoreContext } from './utils/context';
import App from './App';
ReactDOM.render(
<StoreContext.Provider store={store}>
<App />
</StoreContext.Provider>,
document.getElementById('root')
);
点赞收藏不迷路
转载自:https://juejin.cn/post/7205182602365501477