reactjs React-Query获取具有过期访问令牌的陈旧查询

new9mtju  于 2023-04-11  发布在  React
关注(0)|答案(2)|浏览(105)

我们使用react-query从API中获取数据。对于每个API调用,都有一个具有不同查询键的单独钩子,但它们都使用相同的函数callApi(),该函数将api url作为参数来获取数据。
callAPI()钩子中,我们有从authState获取要使用的auth令牌的逻辑。(代码如下)

const useAxios = (baseUrl = config.API_URL) => {
    const history = useHistory()
    const [{ accessToken }] = useAuthState()

    const callApi = useCallback(
        async ({ headers, ...rest }) => {
            try {
                const { data } = await axios({
                    baseURL: baseUrl,
                    headers: {
                        'Content-Type': 'application/json',
                        Authorization: `Bearer ${accessToken}`,
                        ...headers,
                    },
                    ...rest,
                    validateStatus: (status) => status >= 200 && status <= 299,
                })
                return data
            } catch (err) {
                if (err && err.response && err.response.status === 401) {
                    history.push(`${appConfig.APP_SUBPATH}/sessionExpired`)
                } else if (err && err.response && err.response.status === 503) {
                    history.push(`${appConfig.APP_SUBPATH}/underMaintenance`)
                }
                throw err
            }
        },
        [accessToken],
    )

    return callApi
}
export default useAxios
export const useGetItems = () => {
    const callApi = useAxios()

    return useQuery(ALL_ITEMS_KEY, () =>
        callApi({
            method: 'GET',
            url: 'api/v1/items',
        }).then((data) => data.data),
    )
}

问题:令牌刷新后,react-query仍然使用旧令牌重新获取无效的查询,导致***401 UnAuthorized***,尽管状态中的令牌也已更新。
为什么react-query在刷新后仍在使用旧的token?如何防止react-query使用旧的token?

**编辑:**我知道react-query不会因为token更新而自动重取,但是如果查询被标记为无效,则会自动重取,如下图所示。在这种情况下,它会使用第一次调用时使用的旧过期token

queryCache.invalidateQueries((x) => x.queryKey.includes(ALL_ITEMS_KEY))
hpcdzsge

hpcdzsge1#

您在queryKey中没有访问令牌:

useQuery(ALL_ITEMS_KEY)

所以ReactQuery无法理解它应该在数据更改时重新获取数据。将其添加到查询键:

useQuery(
  [...ALL_ITEMS_KEY, accessToken],
  () => callApi(...),
  { enabled: !!accessToken }, // optional?
)

如果没有标记,您也可以选择禁用查询。

kuuvgm7e

kuuvgm7e2#

你在React中遇到了一个陈旧的闭包问题,这是因为你的React依赖(令牌)不是queryKey的一部分。
当重新获取发生时,queryFunction从上次更改键的时间开始使用,因此它仍然可以看到闭包中的旧令牌。
这就是为什么在queryKey中包含所有依赖项如此重要的原因。
我有一个关于闭包的两部分blopost系列,也许这有助于更好地理解这个问题:

现在令牌是一个“特殊”的情况下,我不想将它们包含在QueryKey中。问题是:为什么token来自useAuthState?我猜这是react上下文,但为什么token首先需要存储在react上下文中?从react查询的Angular 来看,没有必要用新的token通知/重新呈现您的组件,除非您也在queryKey中包含该token。
如果您已经在使用axios,那么更好的处理令牌的地方是一个axios拦截器。

相关问题