React钩子导致重新渲染

时间:2020-01-16 20:12:20

标签: reactjs typescript jwt

我有一个钩子,可以从本地存储中读取令牌,并从令牌中解码用户声明。

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,并在第二个渲染上注销用户声明。

为什么渲染两次?

2 个答案:

答案 0 :(得分:1)

useActiveUser钩中的第一行:

const [user, setUser] = useState<IUserTokenClaims | null>(null);

user的初始值设置为null,并且您只将user钩子中的useEffect设置为另一个值,该钩子在(安装后)挂载(初始呈现)。因此,在第一个渲染中,usernull。您可以处理此问题,也可以对代码进行一些修改以避免这种情况。

通常为避免奇怪的渲染,可以添加一个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生命周期方法相同。

  1. 第一个渲染
  2. user的值为null
  3. 已安装组件,已插入useEffect
  4. 从本地存储解析用户
  5. 设置已解析的用户
  6. 触发第二次重新提交