为什么我的反应查询查询在卸载/挂载操作后重新获取?

时间:2020-12-27 08:05:41

标签: reactjs react-query

设置

我有以下 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 次。

Infinite retry

问题似乎来自这样一个事实,即我从正在安装/卸载的多个组件调用 useUser()。当我从 DashboardLogin 中删除重定向逻辑时,react-query 重试 3 次,然后按预期将我带到登录屏幕。

One call to useUser

有趣的事实是 user 查询被标记为过时。如果我将我的 services.user.verify() 实现更改为返回 null 而不是在用户未通过身份验证时抛出错误,则该查询将被标记为新的并且我根本没有这个问题。

问题

  • 即使在重试后仍失败,react-query 总是是否认为查询过时?
  • 调用查询的新组件是否总是导致重试?
  • 有没有办法防止这种情况发生?

1 个答案:

答案 0 :(得分:4)

<块引用>

react-query 是否总是认为即使在重试后仍失败的查询是过时的?

是的。 staleTime 仅用于成功的查询,没有数据的查询(例如因为它们失败)被认为是陈旧的。如果您的查询成功一次,然后在重新获取时失败,则不会自动将其视为过时 - staleTime 现在很重要,因为您已经拥有数据。

<块引用>

调用查询的新组件是否总是导致重试?

当一个组件挂载时,react-query 会触发一个 fetch。这是由于标志 refetchOnMount,所以如果您不想要,可以自定义此标志。根据 retry 标志触发重试,是的,如果触发了提取,则相应地触发重试。

<块引用>

有没有办法防止这种情况发生? 问题似乎来自这样一个事实,即我从正在安装/卸载的多个组件中调用 useUser()。

是的,这似乎是根本原因。您可以使用 refetchOnMount 选项解决此问题,或者可能更好 - 不要重定向到调用 useUser 的路由(并期望用户在场),除非您已经有相关数据用户。例如,如果您的 Login 处于错误状态,您可以挂载 useUser 组件,因为这意味着您未通过身份验证,并且只有在您有用户时才呈现 Dashboard