Blog>
Snippets

Handling Query Invalidation Correctly

Provide an example of proper query invalidation using React Query to ensure data consistency across components and browser tabs.
import { useQuery, useMutation, useQueryClient } from 'react-query';
Import necessary hooks from react-query.
const fetchTodos = async () => {
  const response = await fetch('/api/todos');
  if (!response.ok) {
    throw new Error('Fetching todos failed');
  }
  return response.json();
};
Define a function to fetch todos from an API.
const Todos = () => {
  const queryClient = useQueryClient();
  const { data: todos, isLoading, error } = useQuery('todos', fetchTodos);

  if (isLoading) return 'Loading...';
  if (error) return 'An error occurred: ' + error.message;

  return (
    <ul>{todos.map(todo => (
      <li key={todo.id}>{todo.text}</li>
    ))}</ul>
  );
};
Component that uses useQuery to fetch and display a list of todos.
const addTodo = async (text) => {
  const response = await fetch('/api/todos', {
    method: 'POST',
    body: JSON.stringify({ text }),
    headers: {
      'Content-Type': 'application/json',
    },
  });
  if (!response.ok) {
    throw new Error('Adding todo failed');
  }
  return response.json();
};
Define a function to add a todo by sending a POST request to an API.
const AddTodoForm = () => {
  const queryClient = useQueryClient();
  const { mutate } = useMutation(addTodo, {
    onSuccess: () => {
      // Invalidate and refetch
      queryClient.invalidateQueries('todos');
    },
  });

  const handleSubmit = (event) => {
    event.preventDefault();
    const formData = new FormData(event.target);
    const text = formData.get('text');
    mutate(text);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="text" type="text" required />
      <button type="submit">Add Todo</button>
    </form>
  );
};
Component for adding a new todo. It uses the useMutation hook to add the todo and invalidates the todos query on successful mutation to fetch the updated list.