我有以下 react-query
钩子:
const STALE_TIME_MS = 12 * 60 * 60 * 1000; // 12h
const useUser = () => {
const services = useServices();
const { isLoading, error, data } = useQuery(
'user',
() => services.user.verify(),
{
staleTime: STALE_TIME_MS,
cacheTime: STALE_TIME_MS,
}
);
return {
isLoading,
error,
user: data,
};
};
然后,当孩子住在 App
中时,我有一个 QueryClientProvider
组件:
const App = () => {
const { isLoading } = useUser();
if (isLoading) {
return <Authenticating />;
}
return (
<HashRouter>
<Switch>
<Route path="/login" component={Login} />
<Route path="/" component={Dashboard} />
</Switch>
</HashRouter>
);
}
Login
组件检查用户是否已经登录并将其重定向回 /
:
const Login = () => {
const { user } = useUser();
if (user) {
return <Redirect to="/" />;
}
...
}
Dashboard
组件执行相反的操作:
const Dashboard = () => {
const { user } = useUser();
if (!user) {
return <Redirect to="/login" />;
}
...
};
当 services.user.verify()
发出的请求失败时,react-query
会无限期地重试 user
查询。尽管 react-query
的默认重试次数是 3 次。
问题似乎来自这样一个事实,即我从正在安装/卸载的多个组件调用 useUser()
。当我从 Dashboard
和 Login
中删除重定向逻辑时,react-query
重试 3 次,然后按预期将我带到登录屏幕。
有趣的事实是 user
查询被标记为过时。如果我将我的 services.user.verify()
实现更改为返回 null
而不是在用户未通过身份验证时抛出错误,则该查询将被标记为新的并且我根本没有这个问题。
react-query
总是是否认为查询过时?答案 0 :(得分:4)
react-query 是否总是认为即使在重试后仍失败的查询是过时的?
是的。 staleTime
仅用于成功的查询,没有数据的查询(例如因为它们失败)被认为是陈旧的。如果您的查询成功一次,然后在重新获取时失败,则不会自动将其视为过时 - staleTime
现在很重要,因为您已经拥有数据。
调用查询的新组件是否总是导致重试?
当一个组件挂载时,react-query 会触发一个 fetch。这是由于标志 refetchOnMount
,所以如果您不想要,可以自定义此标志。根据 retry
标志触发重试,是的,如果触发了提取,则相应地触发重试。
有没有办法防止这种情况发生? 问题似乎来自这样一个事实,即我从正在安装/卸载的多个组件中调用 useUser()。
是的,这似乎是根本原因。您可以使用 refetchOnMount
选项解决此问题,或者可能更好 - 不要重定向到调用 useUser
的路由(并期望用户在场),除非您已经有相关数据用户。例如,如果您的 Login
处于错误状态,您可以挂载 useUser
组件,因为这意味着您未通过身份验证,并且只有在您有用户时才呈现 Dashboard
。