reactjstypescriptreact-querytrpc.io

How to update data that React Query has already fetched so that I do not have to refetch all the data?


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()
  })

Solution

  • 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
          })
        },
      })