为什么 useReducer 钩子不更新状态?

Why is useReducer hook not updating state?

我正在研究 React 中的 login/register 个组件,我正在使用 useContext 和 useReducer 挂钩来管理状态。这是我第一次尝试这种方式,我不确定为什么状态没有改变。以下是登录组件的文件。我已经展示了我在哪里登录控制台以及结果是什么。

这是api:

export const login = ({ email, password }) => {

  console.log(email, password); 
  // jennifer@jennifer.com 12345678

  return fetch(`${DEV_AUTH_URL}/signin`, {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      email,
      password,
    }),
  })
    .then((res) => {
      return res.ok
        ? res.json()
        : res.json().then(err => PromiseRejectionEvent.reject(err));
    })
    .then(data => data);
};

这是状态管理器:

const AuthState = (props) => {
  const initialState = {
    token: null,
    isAuth: false,
    errorMsg: null,
    user: {},
  };

  const [state, dispatch] = useReducer(AuthReducer, initialState);
  const history = useHistory();

  const handleLogin = (formData) => {
    login(formData)
      .then((res) => {

        console.log(res); 
        // {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7I…zk3fQ.Qx9zDeXBecToIEScCTDXzkBiTnATHab4cnyg0aSMdLE"}


        res && res.token
          ? dispatch({ type: LOGIN_SUCCESS, payload: res })
          : dispatch({ type: LOGIN_FAIL, payload: res });
      })
      .then(() => {
        closeAllPopups();

        console.log('jwt: ', localStorage.getItem('jwt'));
        // {token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7I…zk3fQ.Qx9zDeXBecToIEScCTDXzkBiTnATHab4cnyg0aSMdLE"}

        console.log('token: ', state.token);
        // token:  null
        console.log('isAuth: ', state.isAuth);
        // isAuth: false

        history.push('/');
      })
      .catch((err) => dispatch({ type: LOGIN_FAIL, payload: err.toString() }));
  };

这是减速器中的内容:

import {
  LOGIN_SUCCESS,
  LOGIN_FAIL,
} from '../types';

export default (state, action) => {
  switch (action.type) {
    case LOGIN_SUCCESS:
      localStorage.setItem('jwt', action.payload.token);
      return {
        ...state,
        token: action.payload.token, // this is not changing state
        isAuth: true, // this is also not changing state
      };
    case LOGIN_FAIL:
      return {
        ...state,
        token: null,
        user: {},
        isAuth: false,
        errorMsg: action.payload,
      };
    default:
      return state;
  }
};

问题

有点不清楚您真正想要的逻辑流程是什么,但是 React 状态更新是异步的,并且调用 handleLogin 回调的渲染周期中的状态包含在生命周期的回调范围内该功能的。仅仅因为 React 状态更新是异步的并不意味着它们可以在任何一个上等待。

解决方案

据我所知,您想调用 login,并在登录成功后分派一个操作、关闭弹出窗口、记录一些值,然后导航到主页。除了记录更新状态之外,这都可以在第一个 thenable.

中完成
const handleLogin = (formData) => {
  login(formData)
    .then((res) => {
      console.log(res); 

      res?.token
        ? dispatch({ type: LOGIN_SUCCESS, payload: res })
        : dispatch({ type: LOGIN_FAIL, payload: res });

      closeAllPopups();
      history.push('/');
    })
    .catch((err) => {
      dispatch({ type: LOGIN_FAIL, payload: err.toString() });
    });
};

使用 useEffect 挂钩记录任何状态更新。

useEffect(() => {
  console.log('jwt: ', localStorage.getItem('jwt'));
  console.log('token: ', state.token);
  console.log('isAuth: ', state.isAuth);
}, [state]);