上下文中的 React useState 不更新
React useState in context does not update
我正在使用 React 创建一个登录页面,登录后应该跟踪用户是否登录。我认为使用 React 上下文和状态挂钩比使用像 Redux 这样大而复杂的东西更容易.
我创建了一个有效的登录功能,在成功登录后,它应该会在我的上下文中更新我的状态。登录有效(我的状态为 200)但我的状态未在我的上下文中更新。
我的'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>
);
};
我的登录函数是这样的
/**
* @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;
}
};
在我的登录表单中,我尝试在成功登录后更新身份验证布尔值
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()));
};
使用此代码,我希望控制台输出为带有 'login successfull' 的打印字符串和打印的布尔值 true。
但似乎我的状态没有更新,即使我调用了 setter.
不知道为什么更新不了,谁能帮帮我?
这段代码完全符合预期。当您更新状态时,它不会立即发生。
const submit = async(e) => {
e.preventDefault();
await login(email, password)
.then((authSuccess) => {
if (authSuccess) {
console.log("login successfull");
authSetter(true);
}
})
.then(() => console.log(authGetter()));
};
当您调用 authSetter(true);
时,状态更新会排队,一旦 then 回调完成,它就会转到链中的下一个 then
,其中有您的 authGetter()
。现在状态更新不会像我解释的那样立即发生,它是排队的。因此,当执行最后一个 then
回调时,排队的状态更新没有发生,您仍然看到 false
这是旧值。
您可以通过以下方式重构您的 AuthProvider
,无需将 setter 包装在函数中,因为它会在更新状态时创建函数的新实例(另一方面,useState
return 是 setter 函数的记忆值),您可以简单地 return authenticated
状态而无需 getter再次遇到同样的问题。
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>
);
};
在您的表单中,您可以多一个useEffect
来检查您是否已成功登录。当 authenticated
状态更新后,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]);
我正在使用 React 创建一个登录页面,登录后应该跟踪用户是否登录。我认为使用 React 上下文和状态挂钩比使用像 Redux 这样大而复杂的东西更容易.
我创建了一个有效的登录功能,在成功登录后,它应该会在我的上下文中更新我的状态。登录有效(我的状态为 200)但我的状态未在我的上下文中更新。
我的'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>
);
};
我的登录函数是这样的
/**
* @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;
}
};
在我的登录表单中,我尝试在成功登录后更新身份验证布尔值
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()));
};
使用此代码,我希望控制台输出为带有 'login successfull' 的打印字符串和打印的布尔值 true。 但似乎我的状态没有更新,即使我调用了 setter.
不知道为什么更新不了,谁能帮帮我?
这段代码完全符合预期。当您更新状态时,它不会立即发生。
const submit = async(e) => {
e.preventDefault();
await login(email, password)
.then((authSuccess) => {
if (authSuccess) {
console.log("login successfull");
authSetter(true);
}
})
.then(() => console.log(authGetter()));
};
当您调用 authSetter(true);
时,状态更新会排队,一旦 then 回调完成,它就会转到链中的下一个 then
,其中有您的 authGetter()
。现在状态更新不会像我解释的那样立即发生,它是排队的。因此,当执行最后一个 then
回调时,排队的状态更新没有发生,您仍然看到 false
这是旧值。
您可以通过以下方式重构您的 AuthProvider
,无需将 setter 包装在函数中,因为它会在更新状态时创建函数的新实例(另一方面,useState
return 是 setter 函数的记忆值),您可以简单地 return authenticated
状态而无需 getter再次遇到同样的问题。
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>
);
};
在您的表单中,您可以多一个useEffect
来检查您是否已成功登录。当 authenticated
状态更新后,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]);