手动实现简易版 react-redux

实现简易版 react-redux

上一节我们实现了简易版的 redux,本节主要实现 react-redux。

同时解决下面问题:

  • 相比 redux, react-redux 有什么好处/做了什么
  • react-redux 用法

react-redux 有什么好处

redux中的 createStore 方法返回三个内置方法getState, dispatch, subscribe。 每次获取属性都需要 store.getState,更新需要 dispatch。

在组件中, 我们想将state和 dispatch方法映射到props上,这样取值就变得非常简单,而 react-redux 就实现了这一层。

react-redux 实现

手动实现简易版 react-redux_第1张图片

如上图,通过 mapStateToProps方法将 state 转为可以传递的 props
dispatch方法有两种形式,obj和function,通过不同的方法来实现将 dispatch方法转为 props
接下来,依次来实现这些方法

Provider

// 创建context
const ValueContext = React.createContext();

export class Provider extends Component {
     
  render() {
     
    return (
      <ValueContext.Provider value={
     this.props.store}>
        {
     this.props.children}
      </ValueContext.Provider>
    );
  }
}


bindActionCreators

作为独立的函数,先说下它的实现。其作用主要是将dispatch对象遍历,取到每个action方法并映射到props

// {
     
//     add: () => ({type: "ADD"})
//   }
export function bindActionCreators(creators, dispatch) {
     
  const obj = {
     };
  for (const key in creators) {
     
    obj[key] = bindActionCreator(creators[key], dispatch);
  }
  return obj;
}

// bindActionCreator(add, dispatch) 转换成 add => dispatch(add({type: "ADD"}))
function bindActionCreator(creator, dispatch) {
     
  return (...args) => dispatch(creator(...args));
}

connect

经过上面步骤,再看connect 函数就简单许多:

export const connect = (
  mapStateToProps = state => state,
  mapDispatchToProps
) => WrappedComponent => {
     
  return class extends Component {
     
    // 此时组件的所有生命周期都能获得this.context
    static contextType = ValueContext;
    constructor(props) {
     
      super(props);
      this.state = {
     
        props: {
     }
      };
    }
    componentDidMount() {
     
      const {
     subscribe} = this.context;
      this.update();
      // 订阅
      subscribe(() => {
     
        this.update();
      });
    }

    update = () => {
     
      const {
     getState, dispatch, subscribe} = this.context;
      //  getState获取当前store的state
      let stateProps = mapStateToProps(getState());
      let dispatchProps;
      // mapDispatchToProps Object/Function
      if (typeof mapDispatchToProps === "object") {
     
        dispatchProps = bindActionCreators(mapDispatchToProps, dispatch);
      } else if (typeof mapDispatchToProps === "function") {
     
        dispatchProps = mapDispatchToProps(dispatch, this.props);
      } else {
     
        // 默认
        dispatchProps = {
     dispatch};
      }
      this.setState({
     
        props: {
     
          ...stateProps,
          ...dispatchProps
        }
      });
    };
    render() {
     
      console.log("this.context", this.context); //sy-log
      return <WrappedComponent {
     ...this.state.props} />;
    }
  };
};

如何使用

以常见的路由守卫举例,调用 connect

// PrivateRoutePage.js
export default connect(
  // mapStateToProps
  ({
     user}) => ({
     isLogin: user.isLogin})
)(
  class PrivateRoute extends Component {
     
    render() {
     
      const {
     isLogin, path, component} = this.props;
      if (isLogin) {
     
        // 登录
        return <Route path={
     path} component={
     component} />;
      } else {
     
        // 去登录,跳转登录页面
        return <Redirect to={
     {
     pathname: "/login", state: {
     redirect: path}}} />;
      }
    }
  }
);

你可能感兴趣的:(#,前端-react,react,redux,react-redux,源码)