SoulCache

Mutation

Learn about SoulCache's mutation system for data modifications

Mutation System

The Mutation System handles data modifications with automatic cache invalidation and optimistic updates.

Core Concepts

Mutations are operations that modify data on the server:

  • Create
  • Update
  • Delete
  • Any side-effect operation

Usage

Basic Mutation

const result = await client.mutate({
  mutationFn: async (variables) => {
    const response = await fetch('/api/users', {
      method: 'POST',
      body: JSON.stringify(variables),
    });
    return response.json();
  },
  variables: { name: 'John' },
});

With Callbacks

const result = await client.mutate({
  mutationFn: createUser,
  variables: { name: 'John' },
  onMutate: (variables) => {
    // Optimistic update - return context
    client.setQueryData(['users'], (old) => [...old, variables]);
    return { previous: client.getQueryData(['users']) };
  },
  onSuccess: (data, variables) => {
    console.log('User created:', data);
  },
  onError: (error, variables) => {
    console.error('Failed:', error);
  },
  onSettled: (data, error, variables) => {
    // Always runs
    client.invalidateQueries(['users']);
  },
});

With Retry

Experimental

The retry and retryDelay parameters are accepted by QueryClient.mutate() but are not currently passed through to MutationEntry. Use MutationEntry.mutateWithRetry() directly for retry behavior.

// Using MutationEntry directly for retry
const entry = client.getMutationCache().create({
  mutationId: 'mut-1',
  mutationFn: createUser,
});
 
const result = await entry.mutateWithRetry(
  { name: 'John' },
  3,   // maxRetries
  1000 // retryDelay (ms)
);

Optimistic Updates

Optimistically update cache before server confirms:

await client.mutate({
  mutationFn: updateUser,
  variables: { id: 1, name: 'Jane' },
  onMutate: (variables) => {
    // Snapshot previous value
    const previous = client.getQueryData(['users']);
 
    // Optimistically update
    client.setQueryData(['users'], (old) =>
      old.map(user => user.id === variables.id ? { ...user, ...variables } : user)
    );
 
    // Return context with snapshot
    return { previous };
  },
  onError: (error, variables) => {
    // Rollback on error (access context via closure)
    client.setQueryData(['users'], previousData);
  },
  onSettled: () => {
    // Refetch after error or success
    client.invalidateQueries(['users']);
  },
});

Mutation States

Mutations go through these states:

StateDescription
idleNot active
pendingCurrently executing
successCompleted successfully
errorFailed

MutationCache

Access the mutation cache directly:

const mutationCache = client.getMutationCache();
 
// Find mutations by status
const pendingMutations = mutationCache.findAll({ status: 'pending' });
 
// Clear all mutations
mutationCache.clear();

Best Practices

Mutation Guidelines

  • Always invalidate related queries — Keep cache consistent
  • Use optimistic updates carefully — Rollback on errors
  • Handle loading states — Show feedback to users
  • Clean up side effects — Use onSettled for cleanup

On this page