为何useEffect不响应localStorage中accessToken的变化?
问题原因
你的第二个useEffect没触发,核心问题出在这行代码:
const token = localStorage.getItem("accessToken");
这行代码只在组件首次渲染或者重新渲染时执行一次,拿到当时localStorage里的token值。之后当service文件移除localStorage中的accessToken时,组件并不会自动重新渲染,这个token变量的值也就不会更新。
而第二个useEffect的依赖数组是这个固定的token值——只要它不变,useEffect就不会重新执行。所以哪怕localStorage里的token被删了,这个token还是初始渲染时的旧值,自然触发不了登出逻辑。
修复方案
这里给你两种可行的修复方式,按需选择:
方案一:监听storage事件+自定义事件
浏览器的storage事件能监听其他标签页/窗口对localStorage的修改,但当前页面内修改不会触发它。所以我们可以结合自定义事件,覆盖当前页面内修改的场景:
const [sessionState, setSessionState] = useState<SessionStateType>({ status: "anon", accessToken: null, }); // 页面加载时初始化登录状态 useEffect(() => { const token = localStorage.getItem("accessToken"); if (token) { setSessionState({ status: "auth", accessToken: token }); } }, []); useEffect(() => { // 监听其他页面修改localStorage的情况 const handleStorageChange = (e: StorageEvent) => { if (e.key === "accessToken" && !e.newValue) { setSessionState({ status: "anon", accessToken: null }); } }; window.addEventListener("storage", handleStorageChange); // 监听当前页面内移除token的自定义事件 const handleTokenRemoved = () => { setSessionState({ status: "anon", accessToken: null }); }; window.addEventListener('tokenRemoved', handleTokenRemoved); // 组件卸载时移除监听 return () => { window.removeEventListener("storage", handleStorageChange); window.removeEventListener('tokenRemoved', handleTokenRemoved); }; }, []);
然后在你的service文件中,移除token时触发自定义事件:
// service文件中移除token的逻辑 localStorage.removeItem("accessToken"); window.dispatchEvent(new CustomEvent('tokenRemoved'));
方案二:把token纳入React状态管理,同步到localStorage
不要直接依赖localStorage作为状态来源,而是把accessToken存在React状态里,同时同步到localStorage。这样状态变化会自动触发组件重新渲染,逻辑更清晰:
// 初始化时从localStorage读取token const [sessionState, setSessionState] = useState<SessionStateType>(() => { const savedToken = localStorage.getItem("accessToken"); return savedToken ? { status: "auth", accessToken: savedToken } : { status: "anon", accessToken: null }; }); // 封装统一的token更新方法 const updateSession = (newToken: string | null) => { if (newToken) { localStorage.setItem("accessToken", newToken); setSessionState({ status: "auth", accessToken: newToken }); } else { localStorage.removeItem("accessToken"); setSessionState({ status: "anon", accessToken: null }); } };
之后在service文件里,不管是获取到新token还是需要移除token,都调用这个updateSession方法,而不是直接操作localStorage。这样组件状态和localStorage始终保持同步,不需要额外监听就能自动触发登出逻辑。
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

