React-query中的查询函数在上下文中使用的值发生更改时不会更新。

3

我在使用useContext hook将用作请求标头中Bearer token的访问令牌传递到查询函数中。但是当访问令牌在一段时间后刷新时,react query仍在查询函数中使用旧的访问令牌。

以下是使用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()会从服务器获取新的访问令牌并将其更新到上下文状态中,然后将其返回。
在useQuery中使用的函数也会传递上下文。
  const fetchUser = async () => {
    const { data } = await authFetch.get('/users');
    return data;
  };

但是当访问令牌被刷新时,useQuery函数仍然在查询中使用旧的访问令牌。我该如何构建我的应用程序,以便在更新后每次查询都使用新的令牌?

1个回答

2
问题在于您在queryFn中封闭了令牌。虽然您没有显示它,但我猜state.accessToken来自useContext或类似方式。
通常情况下,您在queryFn中使用的所有内容都应该是查询键的一部分。因此,修复问题的一种方法是将令牌添加到查询键中。通过与keepPreviousData: true结合使用,您将在创建新缓存条目时继续看到旧数据。

我认为你的方法是合适的,但每次令牌刷新时,所有查询都会被复制,导致旧令牌下的查询无法使用。这种情况是否正常或者会引起任何问题? - Shikhar Mishra
1
它们将在未使用 cacheTime(默认为15分钟)后被垃圾回收。这不应该是一个问题。再考虑一下:如果您设置了axios拦截器,它如何访问react上下文?我认为我还没有完全理解。为什么不将token存储在react之外,并直接访问请求拦截器呢? - TkDodo
我该如何在React之外存储令牌,并在登录和刷新时从React内部更新它? - Shikhar Mishra
更新:所以我使用了两个变量在提供程序组件之外存储令牌。我通过在注册和刷新函数中直接分配新值来直接更新它们,并在axios实例中直接使用它们。我想问一下,如果不使用状态来存储和更新它们,是否会有任何副作用? - Shikhar Mishra
@TkDodo,你的建议在我的情况下似乎有效(至少经过了小规模测试),但它会导致在更新令牌时重新加载查询。有没有一种方法可以确保将来的获取使用最新的令牌(例如使其无效),但不会立即导致刷新? - cattre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接