React应用中Context.Provider的setToken状态更新失效问题
问题分析与解决方案
你的问题核心在于React useState的异步更新特性和闭包捕获旧状态,导致你误以为setToken没更新状态,实际上状态已经在更新,但你在错误的时机访问了旧值。
具体问题点
setToken回调里的闭包问题
你在changeToken里用了setToken的回调函数,但回调里打印的token还是旧值——因为这个回调是在当前渲染周期的闭包中,捕获的是更新前的token状态。React的状态更新后,需要等到下一次渲染才会拿到新值。fetchData递归调用时机错误
在拿到新的accessToken后,你立刻调用await fetchData(),但此时token状态还没完成更新,第二次fetch请求依然会用旧的token,导致看起来状态没更新。
修复步骤
1. 修正changeToken的日志逻辑
去掉setToken的回调,直接打印传入的newToken(这就是即将更新的新值),如果需要监听token的变化,用useEffect:
const changeToken = (newToken) => { setToken(newToken); console.log("buraay geldii change : ", newToken); }; // 新增useEffect监听token变化,打印最新值 useEffect(() => { console.log("yenilenen token ", token); }, [token]);
2. 修改fetchData,支持传入临时token
让fetchData可以接受一个可选的token参数,优先使用传入的新token,避免等待状态更新的异步延迟:
const fetchData = async (overrideToken) => { // 优先用传入的新token,没有则用当前状态的token const currentToken = overrideToken || token; console.log(isVerifyLogin); console.log(currentToken); // 这里打印的是正确的token try { const response = await fetch("http://localhost:8080/api/get-db", { headers: { Authorization: `Bearer ${currentToken}`, }, }); if (!response.ok) { const response2 = await fetch( "http://localhost:8080/api/auth/refreshToken", { method: "POST", headers: { Accept: "application/json", "Content-type": "application/json", }, body: JSON.stringify({ refreshToken: refresh, }), } ); if (response2.ok) { const data2 = await response2.json(); // 先更新状态 changeToken(data2.accessToken); // 用新token直接调用fetchData,不用等状态更新 await fetchData(data2.accessToken); } else { setIsVerifyLogin(false); } } else { setIsVerifyLogin(true); const data = await response.json(); setUsers(data); } } catch (error) { console.error("Error fetching data:", error); setIsVerifyLogin(false); } };
3. 导入useEffect
在TokenProvider的开头补充导入:
import React, { createContext, useState, useEffect } from "react";
为什么这样修复?
- 用
overrideToken参数直接传递新token,绕开了useState异步更新的延迟,确保第二次fetch用的是最新的accessToken。 - 用
useEffect监听token变化,能准确获取到更新后的状态值,避免闭包导致的旧值问题。
内容的提问来源于stack exchange,提问作者imert
相关产品推荐
相关产品推荐

