深入学习react(二) 写个自己的react-redux

738 阅读4分钟

react.jpg

hello,大家好今天让我们一起实现下自己react-redux吧!上一篇我们分享了redux,不懂的可以直接查看额,本篇文章适合有一定基础的react开发人员,用到了react Context api 不懂的可以先查看下,文本较长,建议收藏,废话不说,直接上干货!!!

一、从入口文件开始

首先我们需要在入门文件index.js文件上做如下修改,引入我们自己的文件,这时候因为我们还没有建立文件,自然就报错了,莫慌往下进行

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from '@/pages/home'
// 引入我们自己的provider
import { Provider } from './myReactRedux/provider'
// 引入上期的store
import store from '@/store/store'
ReactDOM.render(
  <React.StrictMode>
    <Provider store={ store }>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

二、创建myReactRedux文件夹

我们在src目录下创建myReactRedux文件夹,在改文件夹下分别创建bindActionCreators.js connect.js createContext.js provider.js,我们先从最简单的provider.js开始创建

import React, { Component } from 'react'
// provider比较简单就是一个高阶组件
class Provider extends Component {
    render() {
        return (
            <div>
                {this.props.children}
            </div>
        )
    }
}
export { Provider }

这里我们就可以页面内容了,那么我们的store数据怎么传递呢?

三、创建createContext.js内容

这里我们需要使用react给我们提供的api方法context,让数据可以向下传递

createContext.js代码比较简单我贴出了,就是原封的react api

import React from 'react'
// react context
const ValueContext = React.createContext();
export default ValueContext

此时我们回过头来给provider.js绑定store

import React, { Component } from 'react'
//引入
import ValueContext from './createContext'
class Provider extends Component {
    render() {
        return (
            // context属性传递,这里去订阅了store的数据传递给了组件
            <ValueContext.Provider value={ this.props.store}>
                {this.props.children}
            </ValueContext.Provider>
        )
    }
}
export { Provider }

此时我们就可以在控制台打印出我们this.props看下了,是不是很简答哇!

四、创建connect.js内容

先分析下结构,connect是一个函数,接收了两个参数并且传递给了组件,代码如下

import React, { Component } from 'react'
// 接收参数,组件,直接将组件返回
export const connect = (
    mapStateToProps,
    mapDispatchToProps
) => WrappedComponent => { 
    return class extends Component {         
        render() {
            return <WrappedComponent />;
        }
    }
}


五、connect函数订阅数据传递给组件

我们的store数据使用了contect向下传递,我们首先引入创建的context获取上下文,和store数据

import React, { Component } from 'react'
import ValueContext from './createContext'
// 接收参数和组件,直接将组件返回
export const connect = (
    mapStateToProps,
    mapDispatchToProps
) => WrappedComponent => { 
    return class extends Component { 
        // 挂载contextType属性
        static contextType = ValueContext
        
        render() {

            return <WrappedComponent />;
        }
    }
}


此时context就被我们挂载到了this上

六、mapStateToProps

state在我们传递过来的mapStateToProps上,他是一个函数,我们直接返回就好了,我们在mount阶段去处理数据,将值传递给组件就可以了

import React, { Component } from 'react'
import ValueContext from './createContext'
// 接收参数和组件,直接将组件返回
export const connect = (
    mapStateToProps,
    mapDispatchToProps
) => WrappedComponent => { 
    return class extends Component { 
        // 挂载contextType属性
        static contextType = ValueContext
        //为了修改props让组件更新变化,需要调用setState,所以这里重新创建下
        constructor(props) {
            super(props);
            this.state = {
                props: {}
            };
        }
        componentDidMount() { 
            this.update();
            //我们在mount阶段去获取一下context中的值
            const { subscribe, getState } = this.context
            subscribe(() => { 
                this.update();
            })
        }
        update = () => { 
            const { getState, dispatch } = this.context;
            //查看一下传递过来的类型
            // console.log(mapStateToProps, mapDispatchToProps);
            //直接返回state的值
            const stateProps = mapStateToProps(getState())
            
            let dispatchProps;
            
            this.setState({
                props: {
                    ...stateProps,
                    ...dispatchProps
                }
            });
        }
        render() {

            return <WrappedComponent {...this.props} {...this.state.props}/>;
        }
    }
}


七、mapDispatchToProps

我们知道mapDispatchToProps可以接受一个对象或者函数,只不过函数需要使用bindActionCreators绑定下dispatch,所以这里要对他们分别进行处理,我们先给出bindActionCreators函数

function bindActionCreator(creator, dispatch) {
    return (...args) => dispatch(creator(...args));
}
// 循环绑定包裹dispatch
function bindActionCreators(creators,dispatch) {
    const obj = {};
    for (const key in creators) {
        obj[key] = bindActionCreator(creators[key],dispatch);
    }
    return obj;
}
export { bindActionCreators }

然后就可以实现我们的mapDispatchToPropsle

import React, { Component } from 'react'
import ValueContext from './createContext'
import { bindActionCreators } from './bindActionCreators'
// 接收参数和组件,直接将组件返回
export const connect = (
    mapStateToProps,
    mapDispatchToProps
) => WrappedComponent => { 
    return class extends Component { 
        // 挂载contextType属性
        static contextType = ValueContext
        constructor(props) {
            super(props);
            this.state = {
                props: {}
            };
        }
        componentDidMount() { 
            this.update();
            //我们在mount阶段去获取一下context中的值
            //看下context中有什么吧
            // console.log(this.context)
            const { subscribe, getState } = this.context
            //这里已经可以看到我们的值了
            // console.log(getState())
            subscribe(() => { 
                this.update();
            })
        }
        update = () => { 
            const { getState, dispatch } = this.context;
            //查看一下传递过来的类型
            // console.log(mapStateToProps, mapDispatchToProps);
            //直接返回state的值
            const stateProps = mapStateToProps(getState())
            
            let dispatchProps;
            if (typeof mapDispatchToProps === "object") {
                // 办理object,分别绑定dispath方法
                dispatchProps = bindActionCreators(mapDispatchToProps,dispatch);
            } else if (typeof mapDispatchToProps === "function") {
                // 绑定dispath方法
                dispatchProps = mapDispatchToProps(dispatch, this.props);
            } else {
                // 直接绑定
                dispatchProps = { dispatch };
            }
            this.setState({
                props: {
                    ...stateProps,
                    ...dispatchProps
                }
            });
        }
        render() {

            return <WrappedComponent {...this.props} {...this.state.props}/>;
        }
    }
}


ok,你学会了吗?快来试试新技能吧!