【问题标题】:Prevent Client Queries from re-running after route changes防止客户端查询在路由更改后重新运行
【发布时间】:2021-03-03 08:42:52
【问题描述】:

我是 ApolloClient/GQL 的新手,但我知道它在缓存方面做得很好,可以防止多个查询。我的应用程序中有一个<RootProvider />,当它挂载时会运行查询以获取我的帐户列表。然后用户选择他们的帐户,它 1) 更新 Global Redux 提供程序,2) 导航到帐户概览页面。如果我随后“切换”我的帐户(使用 setSelectedAccountId('') 清除 selectedAccount),则 URL 将返回到 root 并且查询再次运行。我已经尝试使用useLazyQuery 进行条件查询,并且我在useQuery 本身中尝试了skip 选项,但均未成功。 Skip 本身甚至不会返回缓存数据。

是否有确保数据在路由之间缓存的技巧?

App Wrapper with Global Redux Store:

<Provider store={store}> //contains setSelectedAccountId action & selectedAccountId state
  <Router >
   <App /> 
  </Router >
</Provider>

应用:

          <RootProvider
            setSelectedAccountId={setSelectedAccountId}
            selectedAccountId={selectedAccountId}
          >
              <Switch>
                <Route exact path={routes.root}>
                  <Root setSelectedAccountId={setSelectedAccountId} />
                </Route>
                 <Route exact path={routes.overview()}>
                    <OverviewProvider>
                      <Overview />
                    </OverviewProvider>
                  </Route>
              </Switch>
          </RootProvider>

根提供者:

const RootProvider = ({
  children,
  selectedAccountId,
  setSelectedAccountId,
}: RootProviderProps): ReactElement => {

  const { loading, error, data } = useQuery<{ accounts: RootStateShape[] }>(GET_ACCOUNTS);

  const [selectedAccountDetails, setSelectedAccountDetails] = useState<RootStateShape | null>(null);


  if (loading) {
    return <Loading />;
  }
  if (error) {
    return <div>{JSON.stringify(error)}</div>;
  }

  return (
    <RootStateContext.Provider
      value={{ accounts: data?.accounts || [], selectedAccountDetails, setSelectedAccountDetails }}
    >
      {children}
    </RootStateContext.Provider>
  );
};

还有GET_ACCOUNTS 查询本身:

const GET_ACCOUNTS = gql`
  query getAccounts {
    accounts(accountType: "installers") @rest(type: "AccountsPayload", path: "/accounts?{args}") {
      accountId
      accountName
      isBillable
      recordType
      isActive
    }
  }
`;

我已尝试更新 RootProvider 以使用具有“已安装”状态的 useLazyQuery

const [isMounted, setIsMounted] = useState(false)
const [lazyLoadAccounts, { loading, error, data }] = useLazyQuery<{ accounts: RootStateShape[] }>(
    GET_ACCOUNTS
  );

  useEffect(() => {
    if (!isMounted) {
      lazyLoadAccounts();
      setIsMounted(true);
    }
  }, [data, lazyLoadAccounts]);

感谢任何见解。

【问题讨论】:

    标签: apollo apollo-client apollo-cache-inmemory


    【解决方案1】:

    我能想到的唯一解决方案是复制返回的数据。这样我就可以使用skip 并且仍然获得原始数据的“副本”。我讨厌像这样复制有状态数据,但这似乎是唯一的解决方法?:

    const RootProvider = (props: RootProviderProps): ReactElement => {
      const [skip, setSkip] = useState(false);
      const [queryData, setQueryData] = useState<{ accounts: RootStateShape[] }>();
      const [selectedAccountDetails, setSelectedAccountDetails] = useState<RootStateShape | null>(null);
    
      const { loading, error } = useQuery<{ accounts: RootStateShape[] }>(GET_ACCOUNTS, {
        onCompleted: data => {
          setQueryData(data);
          setSkip(true);
        },
        skip,
      });
    
      if (loading) {
        return <Loading />;
      }
      if (error) {
        return <div>{JSON.stringify(error)}</div>;
      }
    
      return (
        <RootStateContext.Provider
          value={{
            accounts: queryData?.accounts || [],
            selectedAccountDetails,
            setSelectedAccountDetails,
          }}
        >
          {children}
        </RootStateContext.Provider>
    

    【讨论】:

      猜你喜欢
      • 2021-07-31
      • 2021-01-16
      • 2021-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-12
      • 2019-10-08
      相关资源
      最近更新 更多