2

设置

我有以下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当我从and中删除重定向逻辑时Loginreact-query重试 3 次,然后按预期将我带到登录屏幕。

一次调用 useUser

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

问题

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

1 回答 1

5

即使在重试之后,react-query 是否总是认为查询过时?

是的。staleTime只对成功的查询起作用,没有数据的查询(例如因为它们失败)被认为是陈旧的。如果您的查询成功一次,然后在重新获取时失败,它不会自动被认为是陈旧的 -staleTime现在很重要,因为您已经有了数据。

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

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

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

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

于 2020-12-30T08:40:02.573 回答