You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让React Hook实时反映用户登录状态?

解决React Hooks登录状态实时更新问题

问题描述

通过localStorage中的JWT标识用户登录状态,首次加载页面时Hook能正常获取用户数据,但点击「登出」按钮后组件状态未更新,必须刷新页面才生效。

原自定义Hook代码

export const useUser = () => {
    const [token] = useToken();

    const getPayloadFromToken = token => {
        const encodedPayload = token.split('.')[1];
        return JSON.parse(atob(encodedPayload))
    }

    const [user,setUser] = useState(() => {
        if(!token) return null;
        return getPayloadFromToken(token);
    })

    useEffect(() => {
        if(!token) {
            setUser(null);
        } else {
            setUser(getPayloadFromToken(token));
        }
    }, [token]);

    return user;
}

export const useToken = () => {
    const [token, setTokenInternal] = useState(() => {
        return localStorage.getItem('token');
    });

    const setToken = newToken => {
        localStorage.setItem('token',newToken);
        setTokenInternal(newToken);
    }

    return [token, setToken];
}

原导航栏组件代码

const NavigationBar = () => {
    const user = useUser();

    const logOut = () => {
        localStorage.removeItem('token');
    };

    return(
        <>
            <div>{user ? 'logged in' : 'logged out'}</div>
            <button onClick={logout}>Log Out</button>
        </>
    );
}

问题原因

登出时直接操作localStorage.removeItem('token'),但没有更新useToken内部的token状态。useUser的useEffect依赖的是useToken返回的token状态值,状态未变化就不会触发重新计算用户信息,导致组件不更新。另外导航栏里还存在函数名拼写错误:定义的是logOut,但按钮onClick绑定的是logout。

修复方案

1. 优化useToken的setToken方法

处理传入null的情况,自动移除localStorage中的token:

export const useToken = () => {
    const [token, setTokenInternal] = useState(() => {
        return localStorage.getItem('token');
    });

    const setToken = newToken => {
        if (newToken) {
            localStorage.setItem('token', newToken);
        } else {
            localStorage.removeItem('token');
        }
        setTokenInternal(newToken);
    }

    return [token, setToken];
}

2. 修改导航栏组件的登出逻辑

调用useToken提供的setToken方法,而不是直接操作localStorage,同时修正函数名拼写错误:

const NavigationBar = () => {
    const user = useUser();
    const [, setToken] = useToken(); // 获取setToken方法

    const logOut = () => {
        setToken(null); // 通过setToken更新状态
    };

    return(
        <>
            <div>{user ? 'logged in' : 'logged out'}</div>
            <button onClick={logOut}>Log Out</button>
        </>
    );
}

3. 可选:优化useUser的错误处理

为token解析增加异常捕获,避免无效token导致的报错:

export const useUser = () => {
    const [token] = useToken();

    const getPayloadFromToken = (token) => {
        try {
            const encodedPayload = token.split('.')[1];
            return JSON.parse(atob(encodedPayload));
        } catch (err) {
            console.error('解析token失败:', err);
            return null;
        }
    }

    const [user, setUser] = useState(() => {
        if(!token) return null;
        return getPayloadFromToken(token);
    })

    useEffect(() => {
        if(!token) {
            setUser(null);
        } else {
            setUser(getPayloadFromToken(token));
        }
    }, [token]);

    return user;
}

原理说明

通过useToken封装token的读写逻辑,确保每次修改token时都会更新React状态,触发依赖该状态的组件重新渲染。useUser监听token状态变化,自动同步用户信息,实现登录/登出时的实时状态更新。

内容的提问来源于stack exchange,提问作者Spencer Perkins

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 04:54:35