我有一个钩子,可以从本地存储中读取令牌,并从令牌中解码用户声明。
export const useActiveUser = (): { user: IUserTokenClaims | null } => {
const [user, setUser] = useState<IUserTokenClaims | null>(null);
useEffect(() => {
const token = localStorage.getItem("token");
if (!token) setUser(null);
else {
const claims = jwt.decode(token) as IUserTokenClaims;
if (!claims.id || !claims.displayName || !claims.role) setUser(null);
else {
setUser({
id: claims.id,
displayName: claims.displayName,
role: claims.role
});
}
}
}, []);
return { user };
};
如果我然后在类似的组件中使用钩子...
export const SomeComponent: React.FC = () => {
const { user } = useActiveUser();
console.log(user)
if (user) {/* Render stuff if user is logged in */}
else {/* Render stuff if user is not logged in */}
}
log语句将打印null
,并在第二个渲染上注销用户声明。
为什么渲染两次?
答案 0 :(得分:1)
useActiveUser
钩中的第一行:
const [user, setUser] = useState<IUserTokenClaims | null>(null);
将user
的初始值设置为null
,并且您只将user
钩子中的useEffect
设置为另一个值,该钩子在(安装后)挂载(初始呈现)。因此,在第一个渲染中,user
是null
。您可以处理此问题,也可以对代码进行一些修改以避免这种情况。
通常为避免奇怪的渲染,可以添加一个isLoading
状态值,但是,该方法最适合必须异步设置的状态值(例如,通过调用API)。在这种情况下,您可以立即将user
的初始值设置为计算值(因此不需要isLoading
)。
例如,在设置user
状态值并使用user
钩子之前计算useMemo
的值:
export const useActiveUser = (): { user: IUserTokenClaims | null } => {
const user = useMemo(() => {
const token = localStorage.getItem("token");
if (!token) {
return null;
} else {
const claims = jwt.decode(token) as IUserTokenClaims;
if (!claims.id || !claims.displayName || !claims.role) {
return null;
} else {
return {
id: claims.id,
displayName: claims.displayName,
role: claims.role
};
}
}
}, []);
return { user };
};
答案 1 :(得分:1)
它重新渲染两次,因为您是在setUser
挂钩内调用useEffect
,这与类组件上的componentDidMount
生命周期方法相同。
user
的值为null
useEffect
。