#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>