看了 Reducer 的介绍,就感觉很像我初中时候写过的事件驱动 GUI,于是一搜,发现也有人持相同看法。所以建议阅读:

从消息队列的角度来理解 Redux – 逸飞的技术日志 (yifei.me)

下面是本人的笔记,来源不一:

Reducer 的本质 —— 状态转移

一言以蔽之:UI 是状态机,状态转移通过 action 引发,通过 reducer 处理。

  • reducer:状态转移函数,事件处理器。
  • action:事件
import { createStore } from "redux";

function eventHandler(state = {}, event) {
    switch (event.type) {
        case "login":
            console.log(state.token)
            return {
                ...state
            };
        default:
            return state;
    }
}

let store = createStore(eventHandler);

export default store;

发布事件 ——dispatch

一种方法是拿到 store 的实例:

store.dispatch

弊端:相当于全局函数。

但是咱一般也就一个 React 实例,这么干也挺方便。

另一种方法,store 通过 Provider 提供:

import {Provider} from 'react-redux';
import store from 'state/store';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)
import {useSelector, useDispatch} from "react-redux";
const dispatch = useDispatch()

这样的 store 相当于保存在上下文中。

发送一个事件:

store.dispatch({type: "XXX", value: "XXX"})

监听事件 ——selector

const result = useSelector((state) => selectedState)

这里相当于从全局上下文获取状态。所以最好状态不要有复杂的层次结构。

如何用 Hook 替代 Redux

import React, { useReducer } from 'react';

const initState = {}

function eventHandler(state = {}, event) {
    switch (event.type) {
        case "login":
            console.log(event.value.token)
            return {
                ...state
            };
        default:
            return state;
    }
}


export const StoreContext = React.createContext();

export const StoreProvider = (props) => {
  const [state, dispatch] = useReducer(eventHandler, initState);

  return (
    <StoreContext.Provider value={{ state, dispatch }}>
      {props.children}
    </StoreContext.Provider>
  );
};

export default StoreContext

上面创建了 {StoreContext, StoreProvider},我们要将其挂载到 App 上:

...

ReactDOM.render(
  <StoreProvider>{/* 提供全局状态仓库 */}
    <HelmetProvider>{/* 提供修改页面标题功能 */}
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </HelmetProvider>
  </StoreProvider>,
  document.getElementById('root')
);

获取上下文:

const { state, dispatch } = useContext(MyContext);

实例

登录时使用:

import api from 'src/service/api.js'
import {StoreContext} from 'src/service/store'
// ----------------------------------------------------------------------

export default function LoginForm() {
  //...
  const {dispatch} = useContext (StoreContext); // 使用全局状态管理
  //...

  const formik = useFormik({
    initialValues: {
      email: '',
      password: '',
      remember: true
    },
    //...
    onSubmit: async () => {
      const resp = await api.authLogin(formik.values.email, formik.values.password)
      if (resp.data.code === api.CODE_SUCCESS) {
        dispatch({
          type: 'login',
          value: resp.data.data
        })
      }
      // navigate('/dashboard', { replace: true });

    }
  });