我是React Hooks的新手,正在使用react 16.13.1。
我将实现Auth
组件,该组件可以处理登录。
但是,即使currentUser
被响应对象调用,它似乎也无法正确更新状态setCurrentUser
。
此代码有什么问题?
import React, { useState, useEffect } from "react";
import { Route, Redirect } from "react-router-dom";
import { checkLoggedIn } from "utils/Api";
export const Auth = (props) => {
const [currentUser, setCurrentUser] = useState(null);
const [isLoading, setIsLoading] = useState(false);
console.log(currentUser);
useEffect(() => {
const f = async () => {
setIsLoading(true);
console.log(isLoading);
const res = await checkLoggedIn();
if (!!res) { // ==> true
setCurrentUser(res);
console.log(currentUser); // ==> null!
}
setIsLoading(false);
};
f();
});
if (isLoading) {
return <div>loading</div>;
}
console.log(currentUser); // ==> null!
return !!currentUser ? (
<Route children={props.children} />
) : (
<Redirect to={"/login"} />
);
};
答案 0 :(得分:4)
setCurrentUser
异步更新状态,因此之后不能立即使用currentUser
。
但是,您可以使用另一个useEffect
来知道何时更改状态:
useEffect(() => {
// currentUser changed
}, [currentUser])
我还注意到,您没有将空数组传递给您已经拥有的useEffect
,因此它将在每次组件更新时触发。如果您只需要执行一次useEffect
,则必须将空数组作为第二个参数传递,如下所示:
useEffect(() => {
const f = async () => {
// ...
};
f();
}, []);
答案 1 :(得分:2)
由于在React中设置状态的异步特性,调用状态的setter(setCurrentUser)可能是一个问题。我还没有找到任何明确的答案,当我使用React时,它是作为setState异步还是同步。我认为,在这种复杂情况下的最佳解决方案就是使用类。它会为您提供许多生命周期方法,这些方法无法使用钩子重现,并且将更适合auth组件。 React Hooks并不是在所有情况下都可以替代类,而只是一种工具,使您在需要进行简单的改进时就不会破坏现有的代码。
答案 2 :(得分:2)
@germanescobar已回答setCurrentUser
,因此异步更新状态。因此,您需要useEffect
的依赖项列表仅包含currentUser
才能获取最新的状态值。
但是,对于您的用例,您仅对currentUser
是否真实感兴趣,并希望以此为基础将用户重定向到所需页面。因此,您不需要其他useEffect
,因为您不会基于currentUser
执行任何其他副作用。
在实际情况下,您想要显示加载/启动屏幕,直到您能够确定用户是否通过身份验证为止。因此,异步任务完成后,应将isLoading
的初始值更改为true
,并将状态更改为false
。我建议您将州名重命名为:
const [shouldCheckLogin, setShouldCheckLogin] = useState(true)
。
最后,!!null
是false
,而!!{}
是true
。对于object
的值,最好使用null
初始化它们。
console.log(!!null)
console.log(!!{})
答案 3 :(得分:1)
感谢@germanescobar和@Vadim教给我很多东西!
我现在注意到useState
的参数与此问题有关。
改变
const [currentUser, setCurrentUser] = useState(null);
进入
const [currentUser, setCurrentUser] = useState({});
似乎已经解决了未更新的问题(尽管我不知道原因)。