Closed Sashkan closed 1 month ago
You should also post your cache settings, ie the new ApolloClient()
constructor, to make sure that isn't affecting it.
Here's the client config:
Cache content:
export function makeCache() {
return new InMemoryCache({
typePolicies: {
Query: {
fields: {
listItems: {
keyArgs: [
'context',
'groupId',
'pagination',
['sortField', 'filters', 'sortType', 'query', 'limit'],
'selection',
],
},
},
},
},
});
}
Cache
const cache = makeCache();
// Main link for HTTP(S) requests.
const httpLink = split(
(operation) => operation.operationName === 'contactList',
new HttpLink({
uri: `${appConfig.apiUrl}/graphql`,
}),
new BatchHttpLink({
uri: `${appConfig.apiUrl}/graphql`,
}),
);
// WebSocket link.
const wsLink =
process.env.REACT_APP_IS_EXTENSION !== 'true' &&
new WebSocketLink({
uri: `${appConfig.apiWsUrl}/graphql`,
options: {
reconnect: true,
connectionParams: {
authorization: `Bearer ${getAccessToken()}`,
operationName: 'use',
},
},
});
const link =
process.env.REACT_APP_IS_EXTENSION === 'true'
? httpLink
: split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink as WebSocketLink,
httpLink,
);
const maintenanceLink = new ApolloLink((operation, forward) => {
return forward(operation).map((result) => {
const { pathname, hash, search } = window.location;
if (pathname !== '/maintenance' && result.errors) {
const maintenanceError = result.errors.find(
(err) => err.message === MAINTENANCE_MODE,
);
if (maintenanceError) {
localStorage.setItem(
'lastLocationBeforeMaintenance',
JSON.stringify({ pathname, hash, search }),
);
window.location.assign('/maintenance');
}
}
return result;
});
});
// Used to persist cached data event after a page reload.
// Note that user’s cache is flushed if the key changes.
await persistCache({
cache,
storage: new LocalForageWrapper(localForage),
maxSize: false,
key: `apollo-cache-persist-${appConfig.apolloCacheVersion || '0.0.0'}`,
});
this.client = new ApolloClient({
assumeImmutableResults: true,
link: createPersistedQueryLink({ sha256 }).concat(
ApolloLink.from([
maintenanceLink,
onError(({ graphQLErrors }) => {
// TODO: handle errors
if (graphQLErrors) {
graphQLErrors.forEach(({ message, extensions }) => {
if (
extensions?.code === 'UNAUTHENTICATED' ||
message === 'authentication-failed' ||
message === 'unauthorized-missing-user'
) {
logout(this.getClient()!).then(() => {
redirectTo(UserStatus.NOT_CONNECTED, this.history);
});
}
});
}
}),
setContext(() => {
return {
credentials: 'include',
headers: {
authorization: `Bearer ${getAccessToken()}`,
},
};
}),
link,
]),
),
cache,
name: 'front'
version: appConfig.version,
});
Including the values of the variables you have used in that config (e.g. cache
).
My bad, I just updated the comment 🙏
Any updates on this issue?
I believe this might have been a misconception about useQuery
and react-router-dom
.
Generally:
The useQuery
hook will never get data for the wrong variables from the cache. What is does, though, is that while your component is mounted, when you change variables, it holds on to the last data it had until it receives new data for the new variables
.
The purpose of this is to reduce flickering in your UI - if you go from the first page of a list to the second page, you likely want to keep the old data on the screen and just gray it out instead of going back to an almost-empty screen every time the user clicks "next" and having UI jump around.
Now, per default, if both your old page and your new page have the same component, react-router-dom
does not unmount and remount your component - it simply changes props.
From an Apollo Client perspective, that looks like you are simply changing variables, there is no way it could distinguish between a "same page with variable change" and "different page" scenario here.
There are multiple things you can do here:
result.networkStatus
instead of result.loading
- this will give you more granular control over your loading stateskey
to your page in the router. This will lead to React actually unmounting and remounting your component. You will start off with a new component, and the hook will be "freshly mounted" without previous data.
See the React documentation on Resetting state at the same position with focus on resetting state with a keyAs from our side, this is working as intended, I will close this issue. If you have further usage questions, please also visit our Discord and feel free to ask them in the #frontend channel :)
Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Client usage and allow us to serve you better.
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. For general questions, we recommend using StackOverflow or our discord server.
I just setup a small hook using
react-router-dom
andapollo-client
, for a very basic implementation:This looks just like that:
Now, every time I navigate from one list page to another, I still get the old list content before the new one is displayed, resulting in a glitchy effect (previous data appears, then is immediately replaced by the new one)
I made sure that the variables were updated in the query, but still, it seems like apollo will always fetch from the cache for the last call on the query, regardless of the updated variables.
Is there a way to force invalidation? The only workaround I found so far is to set the fetch policy to
network-only
, which is obviously suboptimal...