React 上下文每次使用它时都会返回初始状态 - 尽管 setState

Posted

技术标签:

【中文标题】React 上下文每次使用它时都会返回初始状态 - 尽管 setState【英文标题】:React context returns initial state every time using it - despite setState 【发布时间】:2020-07-03 11:45:57 【问题描述】:

我已经创建了这个简单的身份验证组件。 当应用程序刷新并加载 ContextProvider 时,useEffect 方法被触发并设置用户登录。

看看代码

import React,  createContext, useState, useContext, useEffect  from 'react';
import User from 'utils/User/User';
import useLocale from 'store/LocaleContext';
import  tokenKey  from 'consts';

const AuthContext = createContext();

const initialState =  auth: false, user: null ;

export const AuthContextProvider = ( children ) => 
  const [state, setState] = useState(initialState);
  const  setLanguage  = useLocale();

  const loginUser = user => 
    setLanguage(user.getLanguage());
    user.login();
    setState( ...state, user: user, auth: true );

    setTimeout(() => 
      logOutUser();
    , 2000);
  ;

  const logOutUser = () => 
    console.log(state.user, state); // Output: null, auth: false, user: null
    state.user.logout();
    setState(initialState);
  ;

  useEffect(() => 
    User.Credentials.loginWithToken(localStorage.getItem(tokenKey))
      .then(data => data.data)
      .then(data => 
        if (data.success && data.user) 
          loginUser(new User(data.user));
        
      )
      .catch(err => 
        console.log(err);
        logOutUser();
      );
  , []);

  return (
    <AuthContext.Provider
      value=
        auth: state.auth,
        user: state.user,
        loginUser,
        logout: logOutUser
      
    >
      children
    </AuthContext.Provider>
  );
;

export default () => useContext(AuthContext);

loginUser 方法正确执行,但我想测试logoutUser 函数。 所以我决定在登录 2 秒后运行 logoutUser 函数,但它读取的是旧状态。

当我登录 statestate.user 时,我得到输出:null, auth: false, user: null。如您所见,它显示为initialState 或状态没有改变。

你能告诉我什么问题和我做错了什么吗?

任何帮助将不胜感激

【问题讨论】:

【参考方案1】:

两件事。两者都与 useState 异步有关。

    您需要使用函数作为传递给 setState 的第一个参数。 React 将使用 at-call-time-current 状态调用它,并期望您返回一个 Object 以合并到状态中。

setState(state =&gt; ([...state, user: user, auth: true]));

    您需要使用 Hook useEffect() 以确保您在 console.log() 时获得更新版本的状态。

useEffect(() =&gt; console.log(state) , [state]);

如果这有帮助,请告诉我!

【讨论】:

我尝试了第一个但得到了相同的结果。注意:当我从标题组件(或其他地方)调用注销功能时,它可以正常工作并记录用户详细信息。但是当我从上下文中调用它时,它会返回 initialState @MalkhaziDartsmelidze:你找到解决方案了吗?

以上是关于React 上下文每次使用它时都会返回初始状态 - 尽管 setState的主要内容,如果未能解决你的问题,请参考以下文章

每次更改页面时都会调用 React useEffect (with []) (React Router)

SoundPool 正在加载声音,但每次我播放它时都会显示“样本___ 未准备好”?

每次访问页面时都会触发地理位置代码,而不仅仅是在初始加载或刷新时

如何从 React 中的父类更新我的子组件状态?

每次设置状态时都会调用 Flutter 函数

创建每次选择正确答案时都会增加的分数