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

React-query查询函数在上下文Token更新后未更新,如何解决?

解决React Query在Token刷新后仍使用旧Token的问题

问题描述

我通过useContext钩子在查询函数中传递作为请求头Bearer令牌的access token,但当access token一段时间后刷新时,React Query仍在查询函数中使用旧的access token。相关代码如下:

使用React Query的组件代码

const Profile = () => {
  const { fetchUser} = useAppContext();
  const { data, isLoading, isError, error } = useQuery(
    ['users'],
    fetchUser
  );

  //...
}

上下文传递的Axios拦截器代码

const authFetch = axios.create({
  baseURL: '/api/v1',
  headers: {
    Authorization: `Bearer ${state.accessToken}`,
  },
});

authFetch.interceptors.response.use(
  (response) => response,
  async (error) => {
    const status = error?.response?.status;
    if (status === 401) {
      const config = error.config;
      const accessToken = await refreshAccessToken();
      config.headers['Authorization'] = `Bearer ${accessToken}`;
      return axios.request(config);
    }
    return Promise.reject(error);
  }
);

await refreshAccessToken()从服务器获取新的access token并更新到上下文状态,然后返回该令牌。

上下文传递的查询函数代码

const fetchUser = async () => {
  const { data } = await authFetch.get('/users');
  return data;
};

解决方案

1. 动态添加请求头,避免硬编码Token

问题根源在于axios.create时设置的Authorization头是静态的,实例创建后不会自动同步上下文里的最新Token。改成用请求拦截器每次请求时动态获取最新Token:

const authFetch = axios.create({
  baseURL: '/api/v1',
  // 移除静态的Authorization头
});

// 添加请求拦截器,每次请求时注入最新Token
authFetch.interceptors.request.use(
  (config) => {
    const accessToken = state.accessToken;
    if (accessToken) {
      config.headers['Authorization'] = `Bearer ${accessToken}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 保留响应拦截器的401刷新逻辑,注意用authFetch重发请求
authFetch.interceptors.response.use(
  (response) => response,
  async (error) => {
    const status = error?.response?.status;
    if (status === 401) {
      const config = error.config;
      const accessToken = await refreshAccessToken();
      config.headers['Authorization'] = `Bearer ${accessToken}`;
      return authFetch.request(config); // 用authFetch而非axios,确保走拦截器
    }
    return Promise.reject(error);
  }
);

2. 让React Query感知Token变化,自动更新数据

Token刷新后,即使请求会用新Token,React Query的缓存数据还是旧的,需要让查询关联Token状态:

方法一:将Token加入查询键

把accessToken作为查询键的一部分,Token变化时React Query会自动触发重新查询:

const Profile = () => {
  const { fetchUser, accessToken } = useAppContext();
  const { data, isLoading, isError, error } = useQuery(
    ['users', accessToken], // Token作为查询键的一部分
    fetchUser
  );

  //...
};

方法二:监听Token变化手动触发重查

通过useEffect监听accessToken变化,调用refetch更新数据:

const Profile = () => {
  const { fetchUser, accessToken } = useAppContext();
  const { data, isLoading, isError, error, refetch } = useQuery(
    ['users'],
    fetchUser
  );

  useEffect(() => {
    refetch();
  }, [accessToken, refetch]);

  //...
};

3. 避免查询函数的闭包陷阱

确保fetchUser每次执行时能拿到最新的Token上下文。由于我们已经在请求拦截器中直接访问state.accessToken,每次请求都会获取最新值,不会因为闭包捕获旧状态而出问题。


内容的提问来源于stack exchange,提问作者Shikhar Mishra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 13:20:31