为什么我的 react-query 查询在 unmount/mount 操作后重新获取?
Why is my react-query query refetching after an unmount/mount operation?
设置
我有以下 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
组件,因为 child 位于 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 次。
问题似乎是因为我从 mounting/unmounting 的多个组件调用 useUser()
。当我从 Dashboard
和 Login
中删除重定向逻辑时,react-query
重试 3 次,然后按预期进入登录屏幕。
有趣的是 user
查询被标记为过时。如果我将我的 services.user.verify()
实现更改为 return null
而不是在用户未通过身份验证时抛出错误,查询将被标记为新鲜,我根本没有这个问题。
问题
react-query
是否总是认为查询在重试后仍然失败?
- 调用查询的新组件是否总是导致重试?
- 是否有防止这种情况发生的选项?
Does react-query always consider queries stale when they fail even after the retries?
是的。 staleTime
仅针对成功的查询启动,没有数据的查询(例如,因为它们失败了)被认为是陈旧的。如果您的查询成功一次,然后在重新获取时失败,则它不会自动被视为陈旧 - staleTime
现在很重要,因为您已经有数据。
Does a new component calling the query always result in a retry?
当组件挂载时,react-query 触发获取。这是由于标志refetchOnMount
,所以如果你不想要的话,你可以自定义这个标志。根据 retry
标志触发重试,是的,如果触发提取,则相应地触发重试。
Is there an option to prevent this from happening?
The problem seems to come from the fact that I am calling useUser() from multiple components that are mounting/unmounting.
是的,这似乎是根本原因。您可以使用 refetchOnMount
选项解决此问题,或者,可能更好 - 不要重定向到调用 useUser
的路由(并期望用户在场),除非您已经拥有该数据用户。例如,如果您的 useUser
处于错误状态,您可以安装 Login
组件,因为这意味着您未通过身份验证,并且只有在您有用户时才呈现 Dashboard
。
设置
我有以下 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
组件,因为 child 位于 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 次。
问题似乎是因为我从 mounting/unmounting 的多个组件调用 useUser()
。当我从 Dashboard
和 Login
中删除重定向逻辑时,react-query
重试 3 次,然后按预期进入登录屏幕。
有趣的是 user
查询被标记为过时。如果我将我的 services.user.verify()
实现更改为 return null
而不是在用户未通过身份验证时抛出错误,查询将被标记为新鲜,我根本没有这个问题。
问题
react-query
是否总是认为查询在重试后仍然失败?- 调用查询的新组件是否总是导致重试?
- 是否有防止这种情况发生的选项?
Does react-query always consider queries stale when they fail even after the retries?
是的。 staleTime
仅针对成功的查询启动,没有数据的查询(例如,因为它们失败了)被认为是陈旧的。如果您的查询成功一次,然后在重新获取时失败,则它不会自动被视为陈旧 - staleTime
现在很重要,因为您已经有数据。
Does a new component calling the query always result in a retry?
当组件挂载时,react-query 触发获取。这是由于标志refetchOnMount
,所以如果你不想要的话,你可以自定义这个标志。根据 retry
标志触发重试,是的,如果触发提取,则相应地触发重试。
Is there an option to prevent this from happening? The problem seems to come from the fact that I am calling useUser() from multiple components that are mounting/unmounting.
是的,这似乎是根本原因。您可以使用 refetchOnMount
选项解决此问题,或者,可能更好 - 不要重定向到调用 useUser
的路由(并期望用户在场),除非您已经拥有该数据用户。例如,如果您的 useUser
处于错误状态,您可以安装 Login
组件,因为这意味着您未通过身份验证,并且只有在您有用户时才呈现 Dashboard
。