reactjsreact-query

The result of the invalidateQueries in react-query isn't as expected


I'm practicing using React queries.

In this code, I expected to invalidate only the ['test'] query key. However, the ['todos'] query is invalidated and the data is received again from the server.

Applying useQuery options does not change the results. I would appreciate some help as to what the problem is.

const { data: todos } = useQuery({
    queryKey: ["todos"],
    queryFn: () => getTodos(),
  });

  const { mutate: handleAddTodo } = useMutation({
    mutationFn: addTodo,
    onSuccess: () => {
      queryClient.invalidateQueries(["test"]);
    },
  });
refetchOnWindowFocus: false,
refetchOnMount: false,
refetchOnReconnect: false,

but result is not different.

App.js:

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      refetchOnWindowFocus: false,
      refetchOnMount: false,
      refetchOnReconnect: false,
      staleTime: 10000,
    },
  },
});

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <Todos />
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

export default App;

Todos.js:

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import axios from "axios";
import { useState } from "react";

const getTodos = async (filter) => {
  const { data } = await axios.get(
    `http://localhost:3000/todos${filter ? `?type=${filter}` : ""}`
  );

  return data;
};

const addTodo = async ({ newTodo, newType }) => {
  console.log(newTodo, newType);
  await axios.post("http://localhost:3000/todos", {
    text: newTodo,
    type: newType,
  });
  return;
};

const deleteTodo = async (id) => {
  await axios.delete(`http://localhost:3000/todos/${id}`);
};

const Todos = () => {
  const [newTodo, setNewTodo] = useState("");
  const [newType, setNewType] = useState("study");
  const [filter, setFilter] = useState("");
  const queryClient = useQueryClient();
  const [count, setCount] = useState(0);

  const { data: todos } = useQuery({
    queryKey: ["todos"],
    queryFn: () => getTodos(),
  });

  const { mutate: handleAddTodo } = useMutation({
    mutationFn: addTodo,
    onSuccess: () => {
      queryClient.invalidateQueries(["test"]);
    },
  });

  const handleFilter = (e) => {
    setFilter(e.target.value);
  };

  return (
    <div>
      <input
        value={newTodo}
        onChange={(e) => setNewTodo(e.target.value)}
        placeholder="Add new todo"
      />
      <select value={newType} onChange={(e) => setNewType(e.target.value)}>
        <option value="study">Study</option>
        <option value="exercise">Exercise</option>
      </select>
      <button onClick={() => handleAddTodo({ newTodo, newType })}>
        Add Todo
      </button>

      <div>
        <span>Filter: </span>
        <select value={filter} onChange={handleFilter}>
          <option value="">All</option>
          <option value="study">Study</option>
          <option value="exercise">Exercise</option>
        </select>
      </div>

      <ul>
        {todos &&
          todos.map((todo) => (
            <li key={todo.id}>
              {todo.text} ({todo.type})
              <button onClick={() => deleteTodo(todo.id)}>Delete</button>
            </li>
          ))}
      </ul>
    </div>
  );
};

export default Todos;

Solution

  • So from all element, i think the problem come from a bad syntax on queryClient.invalidateQueries. In fact, we can see in the tanstack/query source code that, the program invalidate all query that match with InvalidateQueryFilters argument. Here, you are giving a list as input so when the program try to findAll query based on your entry, it get all queries because the mathQuery function used by queryCache.findAll function return all time true.

    Try it this way :

    queryClient.invalidateQueries({ queryKey: ['test'] })