Mutations and side effects
-
Use SWR's global and bound mutate (opens in a new tab) APIs to mutate data in the cache when the user performs an action that changes the backend state. This ensures that the cache is updated consistently across the application and omits the need to reload the page to see the changes.
There are two main approaches to mutation with SWR:
- Using the bound mutate (opens in a new tab) function from
useSWR
:
// Using bound mutate to update a specific resource const { data, mutate } = useSWR<Patient>(`/ws/rest/v1/patient/${patientUuid}`); const handleSave = async (updates) => { try { await savePatient(updates); mutate(result); showSnackbar({ title: t('patientSaved', 'Patient saved successfully') }); closeWorkspace(); } catch (error) { showSnackbar({ kind: 'error', title: t('errorSavingPatient', 'Error saving patient') }); } };
- Using the global mutate (opens in a new tab) function for broader cache updates:
import { mutate } from 'swr'; // Using global mutate to update all instances of a resource const handleDeleteVisit = async (visitUuid: string) => { try { await deleteVisit(visitUuid); // Update all cached visit lists mutate('/ws/rest/v1/visit'); // Update the specific visit's data mutate(`/ws/rest/v1/visit/${visitUuid}`); showSnackbar({ title: t('visitDeleted', 'Visit deleted successfully') }); } catch (error) { showSnackbar({ kind: 'error', title: t('errorDeletingVisit', 'Error deleting visit'), subtitle: error?.message }); } };
- Using the bound mutate (opens in a new tab) function from
-
When mutating data that appears in multiple places in your application, make sure to update all relevant cache entries. You can use the
mutate
function with a key matcher to target specific cache entries. Here's an example of updating cohort membership data:const getCohortMembershipUrl = (patientUuid: string) => `${restBaseUrl}/cohortm/cohortmember?patient=${patientUuid}&v=custom:(uuid,patient:ref,cohort:(uuid,name,startDate,endDate))`; // Memoized function to update cohort membership cache const useMutateCohortMembers = (patientUuid: string) => { return useCallback(() => { const key = getCohortMembershipUrl(patientUuid); return mutate( // Only mutate cache entries that exactly match this key (cacheKey) => typeof cacheKey === 'string' && cacheKey === key ); }, [patientUuid]); };
And here's an example of using the mutate hook in a submit handler:
const handleSubmit = useCallback(() => { Promise.all( selected.map((selectedId) => { const patientList = data.find((list) => list.id === selectedId); if (!patientList) return Promise.resolve(); return patientList .addPatient() .then(async () => { // Update the cohort membership data await mutateCohortMembers(); showSnackbar({ title: t('successfullyAdded', 'Successfully added'), kind: 'success', isLowContrast: true, subtitle: `${t('successAddPatientToList', 'Patient added to list')}: ${patientList.displayName}`, }); }) .catch(() => { showSnackbar({ title: t('error', 'Error'), kind: 'error', subtitle: `${t('errorAddPatientToList', 'Patient not added to list')}: ${patientList.displayName}`, }); }); }), ).finally(closeModal); }, [data, selected, closeModal, t, patientUuid]);