Mutationer med useMutation og cache-invalidering
Brug useMutation til at sende data med POST, invalidér relaterede forespørgsler ved succes, så listen automatisk opdateres, og vis optimistisk feedback i brugergrænsefladen, mens anmodningen behandles.
Mutationer med useMutation og cache-invalidering er en gratis React Native Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i React Native Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. React Native Academy-kurset indeholder 4 lektioner i alt.
Hvad er en mutation?
I React Query-terminologien er en mutation enhver handling, der ændrer serverdata — forespørgsler med POST, PUT, PATCH eller DELETE. Hvor useQuery henter og cachelagrer data, håndterer useMutation ændringer af data med tilstande for indlæsning, fejl og succes samt effektive callbacks til sideeffekter.
At adskille forespørgsler (læsning) fra mutationer (skrivning) er et vigtigt begrebsmæssigt mønster. Mutationer cachelagrer ikke deres resultater — de udløser sideeffekter og får derefter relaterede forespørgsler til at hente aktuelle data igen.
Grundlæggende om useMutation
useMutation tager en mutationFn — en asynkron funktion, der udfører skrivehandlingen. Den returnerer en mutate-funktion (eller mutateAsync til Promise-baseret brug), som du kalder, når brugeren udløser handlingen.
I modsætning til useQuery kører mutationer ikke automatisk. De venter på, at du kalder mutate(variables). Hooket giver tilstandene isPending, isError, isSuccess, error og data fra mutationens svar.
import { useMutation } from '@tanstack/react-query';
async function createPost(newPost) {
const response = await fetch('https://api.example.com/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newPost),
});
if (!response.ok) throw new Error('Failed to create post');
return response.json();
}
const { mutate, isPending, isError } = useMutation({
mutationFn: createPost,
});Kald af mutate og mutateAsync
Kald mutate(variables) for at udløse mutationen. Argumentet variables sendes direkte til din mutationFn. mutate starter handlingen uden at vente — den returnerer ikke et Promise. Brug hookets callbacks onSuccess og onError til at reagere på resultatet.
Brug i stedet mutateAsync(variables), når du skal afvente resultatet i en asynkron funktion (for eksempel for at navigere efter et vellykket opslag). Pak altid mutateAsync ind i try/catch — uhåndterede afvisninger medfører fejl.
const { mutate, mutateAsync, isPending } = useMutation({
mutationFn: createPost,
});
// Using mutate (fire-and-forget):
function handleSubmit() {
mutate({ title: 'My Post', body: postContent });
}
// Using mutateAsync (awaitable):
async function handleSubmitAndNavigate() {
try {
const newPost = await mutateAsync({ title: 'My Post', body: postContent });
navigation.navigate('PostDetail', { id: newPost.id });
} catch (err) {
Alert.alert('Error', err.message);
}
}onSuccess: Callback efter en mutation
Callbacken onSuccess kører, når mutationen er gennemført. Den modtager dataene fra mutationsresultatet og de variable, der blev sendt til mutate. Brug onSuccess til at ugyldiggøre relaterede forespørgsler, vise en succesbesked, nulstille formularer eller navigere væk.
Du kan definere onSuccess på hookniveau (til logik, der altid skal anvendes) og også sende den som det andet argument til mutate(variables, { onSuccess }) for tilpasning pr. kald.
import { useMutation, useQueryClient } from '@tanstack/react-query';
const queryClient = useQueryClient();
const { mutate } = useMutation({
mutationFn: createPost,
onSuccess: (newPost, variables) => {
// Refresh the posts list:
queryClient.invalidateQueries({ queryKey: ['posts'] });
// Show success:
Alert.alert('Post created!', newPost.title);
// Reset form:
resetForm();
},
onError: (error) => {
Alert.alert('Error', error.message);
},
});Ugyldiggørelse af cachen efter en mutation
Ugyldiggørelse af cachen er processen med at markere cachelagrede forespørgsler som forældede efter en mutation, så de henter aktuelle data igen. Brug queryClient.invalidateQueries sammen med en forespørgselsnøgle. Delvist match af nøgler understøttes — hvis du ugyldiggør ['posts'], ugyldiggøres alle forespørgsler, hvis nøgle begynder med ['posts'], herunder ['posts', userId].
Ugyldiggørelsen udløser opdateringer i baggrunden for alle aktive (monterede) forespørgsler med matchende nøgler. Komponenter, der bruger disse forespørgsler, viser aktuelle data efter én netværksrundtur.
const { mutate: deletePost } = useMutation({
mutationFn: (postId) =>
fetch('/api/posts/' + postId, { method: 'DELETE' }),
onSuccess: (data, postId) => {
// Invalidate the posts list:
queryClient.invalidateQueries({ queryKey: ['posts'] });
// Also invalidate the specific post's cache:
queryClient.invalidateQueries({ queryKey: ['post', postId] });
},
});Optimistiske opdateringer
Optimistiske opdateringer opdaterer straks brugergrænsefladen, før serveren bekræfter mutationen. Hvis mutationen lykkes, bekræftes den foreløbige ændring. Hvis den mislykkes, rulles brugergrænsefladen tilbage til den tidligere tilstand. Det får interaktioner til at føles øjeblikkelige — du behøver ikke vente på serveren.
Implementér optimistiske opdateringer i onMutate: gem et øjebliksbillede af den aktuelle cache, opdatér cachen med det samme, og rul derefter tilbage i onError efter behov. React Query stiller queryClient.setQueryData til rådighed, så du manuelt kan opdatere cachen.
const { mutate: likePost } = useMutation({
mutationFn: (postId) => fetch('/api/posts/' + postId + '/like', { method: 'POST' }),
onMutate: async (postId) => {
await queryClient.cancelQueries({ queryKey: ['posts'] });
const snapshot = queryClient.getQueryData(['posts']);
// Optimistically add like:
queryClient.setQueryData(['posts'], (old) =>
old.map(p => p.id === postId ? { ...p, likes: p.likes + 1 } : p)
);
return { snapshot }; // return for rollback
},
onError: (err, postId, context) => {
queryClient.setQueryData(['posts'], context.snapshot); // rollback
},
});Mutationsstatus og feedback i brugergrænsefladen
Brug statusfelterne for mutationen til at give passende feedback i brugergrænsefladen. isPending er true, mens mutationen er i gang — deaktivér sendeknappen, og vis en indlæsningsindikator. isSuccess er true efter gennemførelsen — vis en succesbesked. isError er true, hvis den mislykkedes — vis fejlbeskeden.
React Query nulstiller automatisk mutationsstatus efter en konfigurerbar periode angivet med gcTime. Hvis du vil nulstille den manuelt (for eksempel for at give brugeren mulighed for at prøve igen), skal du kalde funktionen reset(), som hooket returnerer.
const { mutate, isPending, isError, isSuccess, error, reset } = useMutation({
mutationFn: submitForm,
});
return (
<View>
<TextInput value={text} onChangeText={setText} editable={!isPending} />
<Button
title={isPending ? 'Submitting...' : 'Submit'}
onPress={() => mutate({ text })}
disabled={isPending}
/>
{isError && <Text style={{ color: 'red' }}>{error.message}</Text>}
{isSuccess && <Text style={{ color: 'green' }}>Saved!</Text>}
</View>
);Direkte opdatering af cachen efter en mutation
I stedet for at ugyldiggøre og hente data igen kan du opdatere cachen direkte med mutationssvaret ved hjælp af queryClient.setQueryData. Det er mere effektivt, når serveren returnerer de opdaterede data i mutationssvaret — du kan føje dem til listen uden en ekstra netværksanmodning.
Dette mønster — at sætte cachen ud fra serverens svar i stedet for at ugyldiggøre den — sparer en netværksrundtur og er nyttigt til lister, hvor du vil tilføje det nye element med det samme.
const { mutate } = useMutation({
mutationFn: createPost,
onSuccess: (newPost) => {
// Append new post to cached list directly:
queryClient.setQueryData(['posts'], (oldPosts) => {
if (!oldPosts) return [newPost];
return [newPost, ...oldPosts]; // prepend new post
});
// No invalidation needed — cache is already up to date!
},
});Globale mutationscallbacks via QueryClient
Du kan definere globale mutationscallbacks i QueryClients defaultOptions.mutations til logning, fejlrapportering eller fornyelse af tokens, der skal gælde for alle mutationer i appen. Lokale mutationsindstillinger tilsidesætter de globale — begge kan eksistere samtidigt.
Et almindeligt anvendelsesområde er en global callback til onError, der kontrollerer, om svaret er 401 Unauthorized, og udløser et logout eller et forløb til fornyelse af tokens for alle mutationer uden at gentage denne logik i hvert enkelt useMutation-kald.
const queryClient = new QueryClient({
defaultOptions: {
mutations: {
onError: (error) => {
// Global error handling for all mutations:
if (error.status === 401) {
handleUnauthorized();
} else {
console.error('Mutation error:', error.message);
}
},
},
},
});Mutationer med filuploads
Mutationer håndterer filuploads ved at modtage FormData som de variable. mutationFn opretter et FormData-objekt og sender det med fetch ved hjælp af indholdstypen multipart/form-data. React Query håndterer indlæsnings- og fejltilstanden på samme måde som ved enhver anden mutation.
Ved store filuploads kan du følge fremdriften ved hjælp af en brugerdefineret fetch-wrapper med XHR, hvor fremdriften gemmes i en separat tilstandsvariabel, der opdateres via mønsteret onUploadProgress.
const { mutate: uploadPhoto, isPending } = useMutation({
mutationFn: async ({ uri, userId }) => {
const formData = new FormData();
formData.append('photo', {
uri,
type: 'image/jpeg',
name: 'photo.jpg',
});
formData.append('userId', userId);
const response = await fetch('/api/photos', {
method: 'POST',
body: formData,
// Do NOT set Content-Type — let fetch set multipart boundary
});
return response.json();
},
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['photos'] }),
});Kædning af mutationer
Ved arbejdsgange, der kræver flere sekventielle handlinger på serveren (for eksempel først at oprette en ordre og derefter behandle betalingen), kan du kæde mutationer ved at bruge mutateAsync sekventielt. Hver mutation kan bruge resultatet fra den foregående som sit input. Pak kæden ind i try/catch for at håndtere fejl.
Hvis et mellemliggende trin mislykkes, kan det være nødvendigt manuelt at rulle tidligere trin tilbage eller udløse kompenserende transaktioner. Design din API til atomicitet, hvor det er muligt, så fejlhåndtering på klientsiden bliver enklere.
const { mutateAsync: createOrder } = useMutation({ mutationFn: apiCreateOrder });
const { mutateAsync: processPayment } = useMutation({ mutationFn: apiProcessPayment });
async function handleCheckout(cartData, paymentInfo) {
try {
const order = await createOrder(cartData);
const payment = await processPayment({ orderId: order.id, ...paymentInfo });
queryClient.invalidateQueries({ queryKey: ['orders'] });
navigation.navigate('OrderConfirmation', { orderId: order.id });
} catch (error) {
Alert.alert('Checkout failed', error.message);
}
}Hurtigt tjek
Test din forståelse af begreberne inden for React Native Mobile Development fra denne lektion.
Opsummering af lektionen
I denne lektion har du lært, at useMutation håndterer skrivehandlinger (POST/PUT/DELETE) med tilstandene isPending, isError og isSuccess, at onSuccess er det primære sted at kalde queryClient.invalidateQueries for at opdatere relaterede cachelagrede data, og at optimistiske opdateringer via onMutate straks opdaterer cachen med et øjebliksbillede, der kan bruges til at rulle tilbage, hvis serverforespørgslen mislykkes. I næste afsnit gemmer vi React Query-cachen i AsyncStorage, så appen kan fungere offline først.
Lær JavaScript med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 30
- Lektioner
- 120
Ofte stillede spørgsmål
Er lektionen “Mutationer med useMutation og cache-invalidering” gratis?
Ja — alle 3 lektioner i læringssporet React Native Academy, inklusive “Mutationer med useMutation og cache-invalidering”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. React Native Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Mutationer med useMutation og cache-invalidering”?
Brug useMutation til at sende data med POST, invalidér relaterede forespørgsler ved succes, så listen automatisk opdateres, og vis optimistisk feedback i brugergrænsefladen, mens anmodningen behandle… Du øver dig i React Native Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på React Native Academy?
Der kræves ingen tidligere erfaring. React Native Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.
Hvor lang tid tager lektionen “Mutationer med useMutation og cache-invalidering”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne React Native Academy-lektion?
Ja. Alle React Native Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- QueryClient, QueryClientProvider og useQuery
- Mutationer med useMutation og cache-invalidering
- Persistens af query-cachen med AsyncStorage
- Konfiguration af background refetch og stale time