使用 Hooks 和 Context 替代 Redux(Typescript 版)

李鹏坤 / 2021-06-11


版本信息

正文

在上一篇文写道,我如何在严格的 ESLint 配置下夹缝生存。

这一篇就是我在不使用 Redux 且在严格的 ESLint 配置下夹缝生存。

直接放代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// store.tsx

import React, { createContext, useReducer } from 'react';

export const ActionType: { [key: string]: string } = {
  onLogin: 'LOGIN',
  onLogout: 'LOGOUT',
};
interface State {
  token?: string;
  state?: State;
  dispatch?: React.Dispatch<Action>;
}
interface Action {
  type: string;
  token?: string;
}
const initialState: State = {};
const store = createContext(initialState);
const { Provider } = store;
const StateProvider = (props: {
  children: JSX.Element | undefined;
}): JSX.Element => {
  const { children } = props;
  const [state, dispatch] = useReducer(
    (states: State, action: Action): State => {
      const { type, token } = action;
      switch (type) {
        case ActionType.onLogin:
          return {
            ...states,
            token,
          };
        case ActionType.onLogout:
          return {
            ...states,
            token: '',
          };
        default:
          return {
            ...states,
          };
      }
    },
    initialState,
  );

  return <Provider value={{ state, dispatch }}>{children}</Provider>;
};

export { store, StateProvider };

这代码没什么好说的,是我参考自以下这两篇博客的。

如何使用?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// index.tsx
import { StateProvider } from '.../store';

ReactDOM.render(
  <React.StrictMode>
    <StateProvider>
      <App />
    </StateProvider>
  </React.StrictMode>,
  document.getElementById('root'),
);

// Login.tsx
import { ActionType, store } from '.../store';
import { useContext } from 'react';

const Login = (): JSX.Element => {
  const { dispatch } = useContext(store);

  const onSubmit = (event: FormEvent<HTMLFormElement>): void => {
    // do some things
    if (dispatch) {
      dispatch({
        type: ActionType.onLogin,
        token: data.token,
      });
    }
  }
}

// XXX.tsx
import { store } from '.../store';
import { renderRoutes, RouteConfigComponentProps } from 'react-router-config';

const XXX = (props: RouteConfigComponentProps): JSX.Element | null => {
  const { route } = props;
  const { state } = useContext(store);
  if (state?.token) {
    return (
      <main className="main">
        {route && renderRoutes(route.children)}
      </main>
    );
  }

  return null;
};