0

我是 ApolloClient/GQL 的新手,但我知道它可以很好地缓存以防止多个查询。我的应用程序中有一个<RootProvider />,它在安装时会运行查询以获取我的帐户列表。然后用户选择他们的帐户,它 1) 更新 Global Redux 提供程序,2) 导航到帐户概览页面。如果我随后“切换”我的帐户(使用 清除 selectedAccount setSelectedAccountId('')),则 URL 将返回到 root 并且查询再次运行。我已经尝试了条件查询,useLazyQuery并且我已经尝试skip了自身内部的选项useQuery,但都没有成功。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]);

我很欣赏任何见解。

4

1 回答 1

0

我能想到的唯一解决方案是复制返回的数据。这样我就可以使用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>
于 2020-11-20T16:11:31.767 回答