简体   繁体   English

上下文中的 React useState 不更新

[英]React useState in context does not update

I'm using React to create a login page which after logging in should keep track if the user is logged in. I figured using the react context and state hook would be easier than using something as big and complex as Redux.我正在使用 React 创建一个登录页面,登录后应该跟踪用户是否已登录。我认为使用 react 上下文和 state 挂钩会比使用像 Redux 这样大而复杂的东西更容易。

I created a login function which works, and after a successfull login it should update my state in my context.我创建了一个有效的登录 function,成功登录后,它应该在我的上下文中更新我的 state。 The login works (i get a status 200) but my state is not updated in my context.登录有效(我得到状态 200)但我的 state 在我的上下文中没有更新。

My 'AuthContext.jsx' looks like this我的 'AuthContext.jsx' 看起来像这样

 import React, { createContext, useState } from "react"; import { login, register } from "../API/apiMethods"; export const AuthContext = createContext(); export const AuthProvider = ({ children }) => { const [authenticated, setAuthenticated] = useState(false); const authSetter = (state) => { setAuthenticated(state); }; const authGetter = () => { return authenticated; }; return ( <AuthContext.Provider value={{ authSetter, authGetter, login, register, }} > {children} </AuthContext.Provider> ); };

My login function looks like this我的登录 function 看起来像这样

 /** * @description Handles login * @param {String} email * @param {String} password * @returns {Boolean} */ export const login = async(email, password) => { try { let authenticated = false; await fetch(BASE_URL + "login", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email, password }), }).then((res) => { authenticated = res.status === 200? true: false; }); return authenticated; } catch (err) { console.log(err); return false; } };

And in my login form i try to update the authentication boolean after a successfull login在我的登录表单中,我尝试在成功登录后更新身份验证 boolean

 const { login, authSetter, authGetter } = useContext(AuthContext); const submit = async(e) => { e.preventDefault(); await login(email, password).then((authSuccess) => { if (authSuccess) { console.log("login successfull"); authSetter(true); } }).then(() => console.log(authGetter())); };

With this code i expected the console output to be a printed string with 'login successfull' and a printed boolean true.使用此代码,我希望控制台 output 是打印的字符串,带有“登录成功”和打印的 boolean 为真。 But it seems my state was not updated even though i did call the setter.但似乎我的 state 没有更新,即使我确实调用了 setter。

我的控制台输出

I don't know why it won't update, can anyone help me?不知道为什么不更新了,谁能帮帮我?

This piece of code does exactly what it is supposed to.这段代码完全符合它的预期。 When you update the state it does not happen immediately.当您更新 state 时,它不会立即发生。

const submit = async(e) => {
  e.preventDefault();

  await login(email, password)
    .then((authSuccess) => {
      if (authSuccess) {
        console.log("login successfull");
        authSetter(true);
      }
    })
    .then(() => console.log(authGetter()));
};

When you call the authSetter(true);当您调用authSetter(true); , the state update is queued and once the then callback completes it goes to the next then in the chain which has your authGetter() . , state 更新已排队,一旦 then 回调完成,它将转到具有您的authGetter()的链中的下一个then Now the state update does not happen immediately as I explained, it is queued.现在 state 更新不会像我解释的那样立即发生,它是排队的。 So when the last then callback is executed the state update which is queued has not happened and you still see false which is the old value.因此,当执行最后一个then回调时,排队的 state 更新没有发生,您仍然看到false是旧值。

You can refactor your AuthProvider in the following way, there is no need to wrap the setter in a function as it would create a new instance of the function when the state is updated ( useState on the other hand returns a memoized value of the setter function) and you can simply return the authenticated state without the getter which again has the same issue. You can refactor your AuthProvider in the following way, there is no need to wrap the setter in a function as it would create a new instance of the function when the state is updated ( useState on the other hand returns a memoized value of the setter function ) 并且您可以简单地返回经过authenticated的 state 而没有同样问题的吸气剂。

import React, { createContext, useState } from "react";
import { login, register } from "../API/apiMethods";

export const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [authenticated, setAuthenticated] = useState(false);

  return (
    <AuthContext.Provider
      value={{
        setAuthenticated,
        authenticated,
        login,
        register,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

In your form, you can have an extra useEffect to check whether you have logged in successfully.在您的表单中,您可以有一个额外的useEffect来检查您是否已成功登录。 the useEffect will run when the authenticated state has been updated.当经过authenticated的 state 更新后, useEffect将运行。

const {
  login,
  setAuthenticated,
  authenticated
} = useContext(AuthContext);

const submit = async(e) => {
  e.preventDefault();
  const authSuccess = await login(email, password);
  if (authSuccess) {
     console.log("login successfull");
     authSetter(true);
  }
};

useEffect(() => {
  console.log(authenticated);
}, [authenticated]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM