apollo 的 useQuery 数据在 client.resetStore() 之后没有更新

Posted

技术标签:

【中文标题】apollo 的 useQuery 数据在 client.resetStore() 之后没有更新【英文标题】:apollo's useQuery data does not update after client.resetStore() 【发布时间】:2021-02-09 15:51:51 【问题描述】:

我遇到了来自@apollo/clientuseQuery 的问题

我有一个Navbar 组件

const Navbar = () => 
  const  loading, data, error  = useQuery(GET_CURRENT_USER);

  console.log('navbar', data)

  return <ReactStuff />

我还有一个UserProfile 组件,它允许用户通过按钮注销。当用户按下按钮时,会运行以下代码:

const 
  getCurrentUser,
  changePassword,
  changePasswordData,
  logoutUser,
 = useUsers();

const logout = () => 
  logoutUser();
  localStorage.removeItem("authToken");
  props.history.push("/");
;

useUsers 是一个自定义钩子,其中包含 resetStore 函数:

const useUser = () => 
  const  client, loading, error, data, refetch  = useQuery(GET_CURRENT_USER);
    
  const logoutUser = () => 
    console.log("firing logout user");
    client
      .resetStore()
      .then((data) => 
        console.log("here in reset store success");
      )
      .catch((err) => 
        console.log("here in error");
      ); // causes uncaught error when logging out.
    ;
    
  return 
    // other useUser functions
    logoutUser
  

现在我无法弄清楚为什么Navbar 组件在按下logout 时没有得到更新。

我有一个withAuth 高阶组件,它执行完全相同的查询,这绝对没问题。用户被发送到 /login 页面,如果我是 console.log(data),它会更新为未定义 - 正如预期的那样。


import  GET_CURRENT_USER  from "../graphql/queries/user";

/**
 * Using this HOC
 * we can check to see if the user is authed
 */
const withAuth = (Component) => (props) => 
  const history = useHistory();
  const  loading, data, error  = useQuery(GET_CURRENT_USER);

  if (error) console.warn(error);
  if (loading) return null;

  if (data && data.user) 
    return <Component ...props />;
  

  if (!data) 
    history.push("/login");
    return "null";
  

  return null;
;

出于某种原因,Navbar 中的这个 useQuery 出于某种原因保留了这些陈旧的数据,我不知道如何使其正常工作。

更新 1:

我已将logoutUser 函数更改为使用clearStore(),同样的事情发生了,导航栏没有更新,但我被重定向到/login 并且withAuth 按预期工作。

const logoutUser = () => 
  client
    .clearStore()
    .then((data) => console.log(data)) // logs []
    .catch((err) => console.log(err)); // no error because no refetch
  ;

【问题讨论】:

您是否通过控制台在导航栏组件内记录用户数据来检查导航栏是否在您注销后重新呈现? 【参考方案1】:

您没有等待商店重置,可能重定向和存储清理发生在重置完成之前,请在完成后尝试这样做

const logout = () => 
  logoutUser(() => 
    localStorage.removeItem('authToken');
    props.history.push('/');
  );
;

const logoutUser = onLogout => 
  console.log('firing logout user');
  client
    .resetStore()
    .then(data => 
      onLogout();
    )
    .catch(err => 
      console.log('here in error');
    ); // causes uncaught error when logging out.
;

【讨论】:

不幸的是,这并没有解决我的问题。我删除了props.history.push('/)`,但仍然面临这个问题。这是因为我正在删除 localStorage authToken,然后 client.resetStore() 正在执行所有查询并出错,因为它没有经过身份验证。 @KarlTaylor 那么您缺少的是导航栏组件中的错误处理,检查它何时收到身份验证错误,并显示未经身份验证的导航栏版本 这不是我所缺少的。我不需要处理 NavBar 组件中的错误,这个用例根本不应该发生错误 - 用户只需注销,并且需要显示新的导航栏。我在这里找到了答案github.com/apollographql/apollo-client/issues/…【参考方案2】:

检查:您是否只有一个 ApolloClient 实例?

在某些情况下,如果您在自定义类或文件中配置 ApolloClient,您可以隐式创建多个 apolloClient 实例,例如通过“import”语句。在这种情况下,您只清除您所做的缓存之一。

【讨论】:

以上是关于apollo 的 useQuery 数据在 client.resetStore() 之后没有更新的主要内容,如果未能解决你的问题,请参考以下文章

Apollo 客户端 useQuery 在 useMutation 后不更新数据

来自 apollo react 的 useQuery 方法的意外结果

Apollo useQuery() - 如果响应相同,则忽略“refetch”

useQuery 返回未定义,但在 gql 操场上返回数据

如何从 Apollo 客户端的 useQuery 获取响应头

如何在 react/apollo 中调用条件 useQuery 钩子