Home > Net >  Why my React Query does not instant update UI after delete?
Why my React Query does not instant update UI after delete?

Time:10-06

The deleted Todo item is still on display after clicking the delete button. It does not immediately remove on display, but on my db.json file it shows that it has been deleted.

I'm using json-server, react vite, react query.

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

export const axiosClient = axios.create({
  baseURL: "http://localhost:8500",
});

const queryClient = new QueryClient();

const SingleTask = ({ listId }) => {
  const { data: taskTodo } = useQuery(
    ["tasks", listId],
    async () => (await axiosClient.get(`/tasks/${listId}/subtasks`)).data,
    {
      initialData: [],
    }
  );

  const deleteTask = useMutation(
    ({id}) => axiosClient.delete(`/subtasks/${id}`),
    {
      onSettled: () => queryClient.invalidateQueries(["tasks"])
    }
  );

  return (
    <>
      {taskTodo
        ?.filter((entry) => entry.status != true)
        .map((list) => (
          <React.Fragment key={list.id}>
            <div className="mt-6">
              <div className="flex justify-between items-center text-sm">
                <div className="flex gap-2">
                  <p>{list.title}</p>
                </div>
                <div className="flex gap-4">
                  <button onClick={() => {
                    deleteTask.mutate(list);
                  }}>
                    Delete
                  </button>
                </div>
              </div>
            </div>
          </React.Fragment>
        ))}
    </>
  );
};

export default SingleTask;

CodePudding user response:

Use refetch to update UI instantly in React Query. Try it, Hope it would work. Thanks.

const { data: taskTodo,refetch } = useQuery(
    ["tasks", listId],
    async () => (await axiosClient.get(`/tasks/${listId}/subtasks`)).data,
    {
      initialData: [],
    }
  );
  const deleteTask = useMutation(
    ({id}) => axiosClient.delete(`/subtasks/${id}`),
    {
      onSettled: () => queryClient.invalidateQueries(["tasks"])
    }
  refetch();
    );

CodePudding user response:

That's because you're invalidating your query. After the query gets invalidated, it will do a refetch of your active query (that is ["tasks", listId], unless you specify otherwise). So you have to wait for the refetch to complete in order to see the update, thus it is not immediate.

If you want it to be "immediate" and if you know what the state will look like, you can use optimistic updates for that.

In your case it could be something like this:

const queryClient = useQueryClient()

useMutation(({id}) => axiosClient.delete(`/subtasks/${id}`), {
  // When mutate is called:
  onMutate: async ({id}) => {
    // Cancel any outgoing refetches (so they don't overwrite our optimistic update)
    await queryClient.cancelQueries(['tasks', id])

    // Snapshot the previous value
    const previousTasks = queryClient.getQueryData(['tasks', id])

    // Optimistically update to the new value
    queryClient.setQueryData(['tasks', id], old => old.filter((t) => t.id !== id))

    // Return a context object with the snapshotted value
    return { previousTasks }
  },
  // If the mutation fails, use the context returned from onMutate to roll back
  one rror: (err, { id }, context) => {
    queryClient.setQueryData(['tasks', id], context.previousTasks)
  },
  // Always refetch after error or success:
  onSettled: (newData, error, { id }) => {
    queryClient.invalidateQueries(['tasks', id])
  },
})
  • Related