手动实现简易版 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 实现

image.png

如上图,通过 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}}} />;
      }
    }
  }
);
发布了171 篇原创文章 · 获赞 246 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/weixin_42042680/article/details/104616071