//connect功能 // 1,接受一个组件,把数据放到组件内部,返回一个组件 // 2,数据发生变化的时候,通知到组件 //高阶组件实现connect // 接受两个参数,防止不传报错需要预设默认值, // 第一个参数是函数,来确定到底返回什么属性,默认原样返回(state=>state), // 第二个是actionCreator的集合,是一个对象, 默认是个空对象 //两次函数嵌套把return 能省的都省了 export const connect=(mapStateToProps=state=>state,mapDispatchToProps={})=>(WrapComponent)=>( //直接返回一个高阶组件 class ConnectComponent extends React.Component{ //必须定义接受全局的store的类型 provider组件提供 static contextTypes={ store:PropTypes.object }; constructor(props,context){ super(props,context); this.state={ props:{} } } //组件初始化完成之后,把store里面的内容注入到props里; componentDidMount(){ const {store}=this.context; //subscribe接受一个函数;我们当前函数就是 去执行this.update()调用,来达到更新; // 我们只要dispatch的动作,就会全部执行一遍subscribe的函数,来更新一遍数据; store.subscribe(()=>this.update()); this.update(); } //获取mapStateToProps和mapDispatchToProps;放入到props里; update(){ //定义dispatch每个actionCreator的工具函数 function bindActionCreator(creator,dispatch) { //透传;就是如果creator有设置参数,直接通通...args解构掉,传过去; return (...args)=>dispatch(creator(...args)) } //定义dispatch过后每个actionCreator的对象集合工具函数 function bindActionCreators(creators,dispatch) { let obj={}; //用对象的每个key名生成数组循环;用每一个key名去 作用到相关的对象; Object.keys(creators).forEach(v=>{ //拿到对象里每个键值对的值 ,也就是actionCreator函数 let creator=creators[v]; //重新生成的obj的每一项就都是被dispatch过的actionCreator; obj[v]=bindActionCreator(creator,dispatch); }); return obj; } //拿到公共上下文的store; const {store}=this.context; //store.getState()当前调用了拿到state;然后根据mapStateToProps的解构规则;返回state的对应值---stateProps; const stateProps=mapStateToProps(store.getState()); // 把mapDispatchToProps用dispatch调用一下来传入的actionCreator对象里的每一个方法;用bindActionCreators实现 const dispatchProps=bindActionCreators(mapDispatchToProps,store.dispatch); //这样就把stateProps,dispatchProps 注入进 props ,并且触发渲染; this.setState({props:{...this.state.props,...dispatchProps,...stateProps}}); } render(){ return <WrapComponent {...this.state.props} /> } } ); //这种写法比较繁琐,所以更推荐上面的两层箭头函数嵌套的写法,更加精炼 // export function connect(mapStateToProps=state=>state,mapDispatchToProps={}) { // return function (WrapComponent) { // return class ConnectComponent extends React.Component{ // render(){ // return <WrapComponent/> // } // } // } // }
其中,bindActionCreators 函数可以写成更加精简 通过强大的reduce数组处理函数
//定义dispatch过后每个actionCreator的对象集合工具函数 function bindActionCreators(creators,dispatch) { // let obj={}; // //用对象的每个key名生成数组循环;用每一个key名去 作用到相关的对象; // Object.keys(creators).forEach(v=>{ // //拿到对象里每个键值对的值 ,也就是actionCreator函数 // let creator=creators[v]; // //重新生成的obj的每一项就都是被dispatch过的actionCreator; // obj[v]=bindActionCreator(creator,dispatch); // }); // return obj; //直接返回这个累加以后的结果,初始值是{}, //reduce方法,入2个参数,第一个参数是回调函数,第二个函数是自重结果的初始值; // 回调函数的入参 可以入4个参数;第一个参数是 计算的返回值(初始值===,reduce入的第二个参数),第二个参数是当前元素; return Object.keys(creators).reduce((rel,item)=>{ rel[item]=bindActionCreator(creators[item],dispatch) return rel; },{}) }