《手写 mini React》简化的Redux

52 阅读1分钟
// 实现一个简化的 React Redux

// 创建 createStore 函数
function createStore(reducer) {
  let state = undefined;
  const listeners = [];

  const getState = () => state;

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach(listener => listener());
  };

  const subscribe = (listener) => {
    listeners.push(listener);
    return () => {
      const index = listeners.indexOf(listener);
      listeners.splice(index, 1);
    };
  };

  dispatch({}); // 初始化 state

  return {
    getState,
    dispatch,
    subscribe
  };
}

// 创建 connect 高阶组件
function connect(mapStateToProps, mapDispatchToProps) {
  return function(Component) {
    class ConnectedComponent extends React.Component {
      constructor(props, context) {
        super(props, context);
        this.state = mapStateToProps(context.getState());
      }

      componentDidMount() {
        this.unsubscribe = this.context.subscribe(() => {
          const newState = mapStateToProps(this.context.getState());
          this.setState(newState);
        });
      }

      componentWillUnmount() {
        this.unsubscribe();
      }

      render() {
        const { dispatch } = this.context;
        const additionalProps = mapDispatchToProps(dispatch);
        return <Component {...this.props} {...this.state} {...additionalProps} />;
      }
    }

    ConnectedComponent.contextType = ReduxContext;

    return ConnectedComponent;
  };
}

// 创建 ReduxContext 上下文
const ReduxContext = React.createContext();

// 创建 Provider 组件
class Provider extends React.Component {
  render() {
    const { store, children } = this.props;
    return (
      <ReduxContext.Provider value={store}>
        {children}
      </ReduxContext.Provider>
    );
  }
}

// 创建 store(与上面 Redux 示例相同)
const store = createStore(reducer);

// 创建 action creators
const increment = () => ({ type: 'INCREMENT' });
const decrement = () => ({ type: 'DECREMENT' });

// 定义 reducer 函数
function reducer(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

// 使用 connect 高阶组件连接 React 组件到 Redux
const ConnectedCounter = connect(
  state => ({ count: state }),
  dispatch => ({
    onIncrement: () => dispatch(increment()),
    onDecrement: () => dispatch(decrement())
  })
)(Counter);

// 使用 Provider 包裹根组件
ReactDOM.render(
  <Provider store={store}>
    <ConnectedCounter />
  </Provider>,
  document.getElementById('root')
);