Запретить повторный запуск клиентских запросов после изменения маршрута

#apollo #apollo-client #apollo-cache-inmemory

#apollo #apollo-клиент #apollo-cache-inmemory

Вопрос:

Я новичок в ApolloClient / GQL, но я понимаю, что он хорошо справляется с кэшированием для предотвращения множественных запросов. У меня есть <RootProvider /> в моем приложении, которое при монтировании запускает запрос, чтобы получить мой список учетных записей. Затем пользователь выбирает свою учетную запись, она 1) обновляет глобального поставщика Redux и 2) переходит на страницу обзора учетной записи. Если я затем «переключу» свою учетную запись (очистите selectedAccount с setSelectedAccountId('') помощью), URL-адрес возвращается к root, и запрос выполняется снова. Я пробовал условный запрос с useLazyQuery помощью и я пробовал skip option внутри useQuery самого, оба безуспешно. Сам Skip даже не вернет кэшированные данные.

Есть ли способ убедиться, что данные кэшируются между маршрутами?

 App Wrapper with Global Redux Store:

<Provider store={store}> //contains setSelectedAccountId action amp; 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>
 

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]);
 

Я ценю любую информацию.

Ответ №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>