Implementing Offline Mutations with useMutation Hook
Illustrate using the useMutation hook for submitting data (create/update/delete operations) while offline and synchronizing these mutations with the backend upon re-establishing a connection.
import { useMutation, useQueryClient } from 'react-query';
import { updateExerciseStatus } from './api';
import AsyncStorage from '@react-native-async-storage/async-storage';
const useOfflineMutation = (key, mutationFn) => {
const queryClient = useQueryClient();
const { mutate } = useMutation(mutationFn, {
onMutate: async variables => {
await queryClient.cancelQueries(key);
const previousValue = queryClient.getQueryData(key);
// Optionally update optimistic UI here
return { previousValue };
},
onError: (err, variables, context) => {
// Optionally rollback optimistic UI here
if (context?.previousValue) {
queryClient.setQueryData(key, context.previousValue);
}
},
onSuccess: (data, variables, context) => {
// Update UI with successful response
queryClient.invalidateQueries(key);
},
onSettled: (data, error, variables, context) => {
// Handle mutation settled state
}
});
return mutate;
};
Defines a custom hook that wraps useMutation for offline support. This hook handles optimistic updates, rollbacks on errors, and automatic UI updates on success. It leverages AsyncStorage for storing mutations when offline.
import { NetInfo } from '@react-native-community/netinfo';
const submitMutation = async (payload) => {
const isConnected = await NetInfo.fetch().then(state => state.isConnected);
if (!isConnected) {
// Store mutation payload in AsyncStorage for later execution
const currentMutations = await AsyncStorage.getItem('offlineMutations') || '[]';
const mutations = JSON.parse(currentMutations);
mutations.push(payload);
await AsyncStorage.setItem('offlineMutations', JSON.stringify(mutations));
} else {
// Directly perform mutation as the device is online
useOfflineMutation('key', updateExerciseStatus)(payload);
}
};
Defines the logic for handling mutations when the device is offline. It checks the device's connectivity status and stores the mutation in AsyncStorage if offline. Otherwise, it performs the mutation immediately.
const syncOfflineMutations = async () => {
const mutations = JSON.parse(await AsyncStorage.getItem('offlineMutations') || '[]');
mutations.forEach(mutation => {
useOfflineMutation('key', updateExerciseStatus)(mutation);
// Remove each processed mutation from AsyncStorage here
});
};
Implements the function to synchronize mutations stored in AsyncStorage when the device goes back online. It iterates over each stored mutation, performs them, and should remove them from storage upon successful completion.