I'm writing a React component using Apollo GraphQL (with React Apollo Hooks, but this makes no difference).
Here is my query:
const { data, error, loading } = useQuery(ListContacts, {
fetchPolicy: 'cache-and-network'
// variables: { limit: 1000 }
});
And here is my function that does the mutation:
const createContact = useMutation(gql(mutations.createContact));
const deleteContact = useMutation(gql(mutations.deleteContact));
const updateContact = useMutation(gql(mutations.updateContact));
async function handleContactSave(contact) {
const isEmpty = allStringFieldsAreEmptyFromContact(contact);
const { id, ...processedContact } = replaceEmptyStringsWithNull(contact);
const idIsInArray = includesContactWithId(id)(contacts);
try {
if (isEmpty) {
if (idIsInArray) {
await deleteContact({
variables: { input: { id } },
optimisticResponse: () => ({ deleteContact: { id } }),
update: (cache, { data: { deleteContact } }) => {
const query = ListContacts;
const data = cache.readQuery({ query });
data.listContacts.items = data.listContacts.items.filter(
item => item.id !== deleteContact.id
);
cache.writeQuery({ query, data });
}
});
}
} else {
if (idIsInArray) {
await updateContact({
variables: { input: { id, ...processedContact } },
optimisticResponse: () => ({
updateContact: { __typename: 'Contact', id, ...processedContact }
}),
update: (cache, { data: { updateContact } }) => {
const query = ListContacts;
const data = cache.readQuery({ query });
data.listContacts.items = [
...data.listContacts.items.filter(
item => item.id !== updateContact.id
),
updateContact
];
cache.writeQuery({ query, data });
}
});
} else {
await createContact({
variables: { input: { ...processedContact } },
optimisticResponse: () => ({
createContact: {
__typename: 'Contact',
id: uuid(),
...processedContact
}
}),
update: (cache, { data: { createContact } }) => {
const query = ListContacts;
const data = cache.readQuery({ query });
data.listContacts.items = [
...data.listContacts.items.filter(
item => item.id !== createContact.id
),
createContact
];
cache.writeQuery({ query, data });
}
});
}
}
} catch (error) {
console.log(error);
}
}
As soon as I comment out the variables
key with the limit
the UI does not update optimistically any more. With the value commented out it does. What is going wrong here?
The writeQuery
method also accepts a variables
value. Every combination of query
and variables
is treated as a separate query by Apollo. So if one Query
component (or hook) uses a limit of 100
and another uses a limit of 50
, when writing your update
function, you'll need to call writeQuery
for both of these queries, passing in a different value for variables
each time:
cache.writeQuery({ query, data, variables: { limit: 100 } })
cache.writeQuery({ query, data, variables: { limit: 50 } })
This is a know limitation of the client. In effect, you need to keep track of the variables through local state in order to correctly call writeQuery
when your update
function is called. This can be, understandably, a huge hassle. Luckily, you can utilize apollo-link-watched-mutation to get around the issue.