React Native Academy · Les

Mutaties met useMutation en cache-invalidatie

Gebruik useMutation om gegevens te POST'en, invalideer gerelateerde queries bij succes zodat de lijst automatisch wordt vernieuwd en toon optimistische UI-feedback zolang het verzoek wordt verwerkt.

Les 2 van 413 stappen

Mutaties met useMutation en cache-invalidatie is een gratis React Native Academy-les op CoddyKit. Dit is les 2 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject React Native Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus React Native Academy bevat in totaal 4 lessen.

Wat is een mutatie?

In de terminologie van React Query is een mutatie elke bewerking die servergegevens wijzigt — POST-, PUT-, PATCH- of DELETE-aanvragen. Terwijl useQuery gegevens ophaalt en in de cache opslaat, verwerkt useMutation wijzigingen in gegevens met laad-, fout- en successtatussen, plus krachtige callbacks voor neveneffecten.

Het scheiden van query's (lezen) en mutaties (schrijven) is een belangrijk conceptueel patroon. Mutaties slaan hun resultaten niet in de cache op — ze activeren neveneffecten en zorgen er vervolgens voor dat gerelateerde query's opnieuw actuele gegevens ophalen.

Basisprincipes van useMutation

useMutation ontvangt een mutationFn — een asynchrone functie die de schrijfbewerking uitvoert. De hook retourneert een functie mutate (of mutateAsync voor gebruik met Promises) die je aanroept wanneer de gebruiker de actie uitvoert.

In tegenstelling tot useQuery worden mutaties niet automatisch uitgevoerd. Ze wachten totdat je mutate(variables) aanroept. De hook biedt de statusvelden isPending, isError, isSuccess, error en data uit de respons van de mutatie.

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,
});

mutate en mutateAsync aanroepen

Roep mutate(variables) aan om de mutatie te starten. Het argument variables wordt rechtstreeks aan je mutationFn doorgegeven. mutate start de bewerking zonder op het resultaat te wachten — de functie retourneert geen Promise. Gebruik de callbacks onSuccess en onError van de hook om op het resultaat te reageren.

Gebruik mutateAsync(variables) wanneer je het resultaat in een asynchrone functie moet afwachten, bijvoorbeeld om na een geslaagde post naar een andere pagina te navigeren. Plaats mutateAsync altijd in try/catch — niet-afgehandelde afwijzingen veroorzaken fouten.

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 na een mutatie

De callback onSuccess wordt uitgevoerd wanneer de mutatie succesvol is voltooid. De callback ontvangt de resultaatgegevens van de mutatie en de variabelen die aan mutate zijn doorgegeven. Gebruik onSuccess om gerelateerde query's ongeldig te maken, feedback over succes te tonen, formulieren te resetten of naar een andere pagina te navigeren.

Je kunt onSuccess op hookniveau definiëren voor logica die altijd van toepassing is en de callback ook als tweede argument doorgeven aan mutate(variables, { onSuccess }) voor aanpassingen per aanroep.

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);
  },
});

De cache ongeldig maken na een mutatie

De cache ongeldig maken is het proces waarbij query's in de cache na een mutatie als verouderd worden gemarkeerd, zodat ze nieuwe gegevens ophalen. Gebruik queryClient.invalidateQueries met een query-sleutel. Gedeeltelijk overeenkomende sleutels worden ondersteund — door ['posts'] ongeldig te maken, maak je alle query's ongeldig waarvan de sleutel met ['posts'] begint, waaronder ['posts', userId].

Door het ongeldig maken worden query's die actief zijn (gemonteerd) en overeenkomende sleutels hebben, op de achtergrond opnieuw opgehaald. Componenten die deze query's gebruiken, tonen binnen één netwerkronde nieuwe gegevens.

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] });
  },
});

Optimistische updates

Met optimistische updates werk je de gebruikersinterface al bij voordat de server de mutatie bevestigt. Als de mutatie slaagt, wordt de voorlopige wijziging bevestigd. Als de mutatie mislukt, wordt de gebruikersinterface teruggezet naar de vorige status. Hierdoor voelen interacties direct aan — je hoeft niet op de server te wachten.

Implementeer optimistische updates in onMutate: sla de huidige momentopname van de cache op, werk de cache onmiddellijk bij en zet deze indien nodig terug in onError. React Query biedt queryClient.setQueryData om de cache handmatig bij te werken.

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
  },
});

Mutatiestatus en feedback in de gebruikersinterface

Gebruik statusvelden van de mutatie om passende feedback in de gebruikersinterface te geven. isPending is true zolang de mutatie wordt uitgevoerd — schakel de verzendknop uit en toon een laadanimatie. isSuccess is true nadat de mutatie is voltooid — toon een succesbericht. isError is true als de mutatie is mislukt — toon het foutbericht.

React Query reset de mutatiestatus automatisch na een configureerbare periode gcTime. Als je de status handmatig wilt resetten, bijvoorbeeld zodat de gebruiker het opnieuw kan proberen, roep je de functie reset() aan die door de hook wordt geretourneerd.

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>
);

De cache rechtstreeks bijwerken na een mutatie

In plaats van de cache ongeldig te maken en gegevens opnieuw op te halen, kun je de cache rechtstreeks bijwerken met de respons van de mutatie via queryClient.setQueryData. Dit is efficiënter wanneer de server de bijgewerkte gegevens in de respons van de mutatie retourneert — je kunt deze aan de lijst toevoegen zonder een extra netwerkaanvraag.

Dit patroon — de cache bijwerken vanuit de serverrespons in plaats van deze ongeldig te maken — bespaart een netwerkronde en is nuttig voor lijsten waaraan je het nieuwe item direct wilt toevoegen.

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 callbacks voor mutaties via QueryClient

Je kunt globale callbacks voor mutaties definiëren in defaultOptions.mutations van QueryClient voor logging, foutrapportage of het vernieuwen van tokens die op elke mutatie in de app moeten worden toegepast. Lokale opties voor mutaties overschrijven globale opties — beide kunnen naast elkaar bestaan.

Een veelvoorkomend gebruik is een globale callback onError die controleert op 401 Unauthorized-responsen en voor elke mutatie een uitlog- of tokenvernieuwingsproces start, zonder deze logica in elke afzonderlijke aanroep van useMutation te herhalen.

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);
        }
      },
    },
  },
});

Mutaties met bestandsuploads

Mutaties verwerken bestandsuploads door FormData als variabelen te accepteren. De mutationFn maakt een FormData-object en verstuurt dit met fetch, waarbij het inhoudstype multipart/form-data wordt gebruikt. React Query beheert de laad- en foutstatus op dezelfde manier als bij elke andere mutatie.

Houd bij grote bestandsuploads de voortgang bij met een aangepaste fetch-wrapper met XHR. Sla de voortgang op in een afzonderlijke statusvariabele die wordt bijgewerkt volgens het patroon 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'] }),
});

Mutaties aan elkaar koppelen

Voor werkstromen waarvoor meerdere opeenvolgende bewerkingen op de server nodig zijn, bijvoorbeeld eerst een bestelling maken en daarna de betaling verwerken, koppel je mutaties door mutateAsync achter elkaar te gebruiken. Elke mutatie kan het resultaat van de vorige mutatie als invoer gebruiken. Plaats de keten in try/catch voor foutafhandeling.

Als tussenstappen mislukken, moet je eerdere stappen mogelijk handmatig terugdraaien of compenserende transacties starten. Ontwerp je API waar mogelijk voor atomiciteit om foutherstel aan de clientzijde eenvoudiger te maken.

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);
  }
}

Korte controle

Controleer je begrip van de concepten voor mobiele ontwikkeling met React Native uit deze les.

Samenvatting van de les

In deze les heb je geleerd dat useMutation schrijfbewerkingen (POST/PUT/DELETE) verwerkt met de statusvelden isPending, isError en isSuccess, dat onSuccess de belangrijkste plek is om queryClient.invalidateQueries aan te roepen en gerelateerde gegevens in de cache te vernieuwen, en dat optimistische updates via onMutate de cache onmiddellijk bijwerken met een momentopname om terug te draaien als de serveraanvraag mislukt. Hierna bewaren we de React Query-cache in AsyncStorage voor offline-first-gedrag.

Gratis beginnen

Leer JavaScript met een AI-tutor — gratis

Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.

Cursussen
30
Lessen
120

Veelgestelde vragen

Is de les “Mutaties met useMutation en cache-invalidatie” gratis?

Ja — je kunt hier op het web alle 3 lessen van het leerpad React Native Academy, waaronder “Mutaties met useMutation en cache-invalidatie”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus React Native Academy bevat in totaal 4 lessen.

Wat leer ik in “Mutaties met useMutation en cache-invalidatie”?

Gebruik useMutation om gegevens te POST'en, invalideer gerelateerde queries bij succes zodat de lijst automatisch wordt vernieuwd en toon optimistische UI-feedback zolang het verzoek wordt verwerkt. Je oefent met React Native Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.

Heb ik ervaring nodig om met React Native Academy te beginnen?

Ervaring vooraf is niet nodig. React Native Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 2 van 4.

Hoe lang duurt de les “Mutaties met useMutation en cache-invalidatie”?

De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.

Kan ik code schrijven en uitvoeren in deze les over React Native Academy?

Ja. Elke les over React Native Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.

Alle lessen in deze cursus

  1. QueryClient, QueryClientProvider en useQuery
  2. Mutaties met useMutation en cache-invalidatie
  3. De querycache bewaren met AsyncStorage
  4. Configuratie van refetch op de achtergrond en stale time
← Terug naar React Native Academy