3

Currently, my code looks like this. When mutation is successful, I have to refetch all the data because tasks will not be updated. How can I update the client-side tasks when I submit or delete a task?

  const { data: sessionData } = useSession()

  const {
    data: tasks,
    refetch: refetchTasks,
  } = api.task.getAll.useQuery(undefined, {
    enabled: sessionData?.user !== undefined,
  })

  const createTask = api.task.create.useMutation({
    onSuccess: async () => await refetchTasks(),
  })

  const createTaskValues = (values: { title: string }) =>
    createTask.mutate({ title: values.title })

  const deleteTask = api.task.delete.useMutation({
    onSuccess: async () => await refetchTasks(),
  })

PS

Using useContext() is better than calling refetch function unless you want to refetch data every time.

const utils = api.useContext()

  const createTask = api.task.create.useMutation({
    onSuccess: () => utils.task.getAll.invalidate()
  })

  const createTaskValues = (values: { title: string }) =>
    createTask.mutate({ title: values.title })

  const deleteTask = api.task.delete.useMutation({
    onSuccess: () => utils.task.getAll.invalidate()
  })
lightbluepoppy
  • 141
  • 1
  • 10

3 Answers3

1

First, provide a query key to your useQuery call (https://tanstack.com/query/latest/docs/react/guides/query-keys).

Then in the onSuccess of your mutation, you'll invalidate that query key, which will essentially cause React Query to re-fetch the data for you (https://tanstack.com/query/latest/docs/react/guides/query-invalidation).

For example:

const { data: sessionData } = useSession()

const {
  data: tasks,
  refetch: refetchTasks,
} = api.task.getAll.useQuery(["tasks"], {
  enabled: sessionData?.user !== undefined,
})

const queryClient = useQueryClient();

const createTask = api.task.create.useMutation({
  onSuccess: () => {
    queryClient.invalidateQueries(["tasks"]);
  },
})
Jeff F.
  • 1,039
  • 5
  • 11
  • `["tasks"]` in useQuery function throws an error; Argument of type `String[]` is not assignable to parameter of type `void` – lightbluepoppy Apr 22 '23 at 20:21
  • I don't know what `api.task.getAll.useQuery` is in your code base. Do you have some wrapper around react-query? – Jeff F. Apr 23 '23 at 00:50
0

I figured out the solution by myself. I use tRPC and it provides its own callback function setData() to mutate cache. tRPC is a wrapper of React-Query though.

This way, when mutation on the database was successful, I can mutate the cache as well.

Now I have to use global state manager like Zustand less!

  const { data: sessionData } = useSession()

  const { data: tasks } = api.task.getAll.useQuery(undefined, {
    enabled: sessionData?.user !== undefined,
  })

  const utils = api.useContext()

  const createTask = api.task.create.useMutation({
    onSuccess: newTask => {
      utils.task.getAll.setData(undefined, prevTasks => {
        if (prevTasks === undefined) return [newTask]
        console.log([...prevTasks, newTask])
        return [...prevTasks, newTask]
      })
    },
  })

  const createTaskValues = (values: { title: string }) =>
    createTask.mutate({ title: values.title })

  const deleteTask = api.task.delete.useMutation({
    onSuccess: deletedTask => {
      utils.task.getAll.setData(undefined, prevTasks => {
        const tasksWithoutDeletedTask = prevTasks?.filter(
          task => task.id !== deletedTask.id
        )
        console.log(tasksWithoutDeletedTask)
        return tasksWithoutDeletedTask
      })
    },
  })
lightbluepoppy
  • 141
  • 1
  • 10
0

You can look this doc

You can update from mutation response, so you don't need refetch from GET API again.

yang zhou
  • 148
  • 6