ReactQuery make refetch with old data

Viewed 722

I use ReactQuery in My App. I create a custom hook with the state. I export function that changes this state in my application. I expect that after changing state I will make a re-fetch with a new state. But it does not happen. I add UseEffect on change state and execute refetch() after my state is changed, but it fetches with previous data, with a body before I updated the state.

So inside UseEffect I see that body is changed(with new data) -> call refetch -> useQuery call ()=>fetchCommissionsData(body), but with old body(not new data)

I'm using: "react": "^18.1.0", "react-query": "^3.39.1"

import React, { useState, useEffect } from 'react'
import { getCommissionsData, getSummary } from "../utils/apis";
import { queryKeys } from "../utils/constants";
import { useMutation, useQueryClient, useQuery } from "react-query";

//REST API
const fetchCommissionsData = async (request) => {
    const response = await getCommissionsData(request)
    return response
}

export function useCommissionsData() {
const [body, setBody] = useState(null)
const queryClient = useQueryClient()
const searchValues = queryClient.getQueryData(queryKeys.searchValues)
    
//get data from client,add some extra parameters  and update state with request body
const getCommissionsData = (data) => {
    const body = {
        ...data,
        movementType: searchValues.movementType,
        viewType: searchValues.viewType,
        summaryType: searchValues.summaryType
    }
    setBody(body)
}

//Effect: refetch query to get new commissions data on every change with request body
useEffect(() => {
    refetch()
}, [body])

//default data is empty array
const fallback = [];
const { data = fallback, refetch } = useQuery([queryKeys.commissionsData], () => fetchCommissionsData(body), {
    refetchOnWindowFocus: false,
    enabled: false // turned off by default, manual refetch is needed
});

return { data, getCommissionsData }
1 Answers

The misconception here is that you're thinking in an imperative way: "I have to call refetch if something changes, so I need an effect for that."

react-query however is quite declarative, so you don't need any of that. refetch is meant for refetching with the same parameters. That's why it also doesn't accept any variables as input.

Judging from your code, you want to fetch once body is set. This is best done by:

  • adding body to the queryKey
  • disabling the query only when body is null:
const [body, setBody] = useState(null)
const { data = fallback } = useQuery(
  [queryKeys.commissionsData, body],
  () => fetchCommissionsData(body),
  {
    enabled: body === null
  }
);

Then, all you need to do is call setBody with a new value, and react-query will automatically trigger a refetch with the new body values. Also, it will cache per body, so if you go back from one filter to the other, you will still have cached data.

Related