react-query: Refetch Query only if the state variable is changed

Ashik picture Ashik · Nov 14, 2020 · Viewed 8.9k times · Source

I have a select option menu. So, When a user selects an option, I want send a GET/ request to the server with that option and recieve the filtered data from server.

This can be achived using useEffect(() => {// send the request}, [criteria])

Because, useEffect ensures that the request will send to server only if the setCriteria is finished.

But, I am using react-query library. so that, it is not allowed to use useQuery inside useEffect.

As A result, the request is send to server before it the setState is completed. So that, server gets the previous selected value, not the currently selected value.

onChange:

<select
  name="filter"
  value={criteria}
  onChange={async (e) => {
    setCriteria(e.target.value);
  }}
>
  <option>Most recent First</option>
  <option>Price: Low to High</option>
  <option>Price: High to Low</option>
</select>;

Fetch posts:

 const FetchPosts = async () => {
    const {
      data: { posts },
    } = await axios.get(`${process.env.API_URL}/api/posts`, {
      params: {
        filter: criteria,
      },
    });

    return posts;
  };

 useQuery("posts", FetchPosts);

 const posts = queryCache.getQueryData("posts");

Answer

Chanandrei picture Chanandrei · Nov 14, 2020

You can use your criteria as query key. Whenever a query's key changes, the query will automatically update.

const FetchPosts = async ({criteria}) => {
    console.log(criteria) //from useQuery key

    //your get api call here with criteria params

    return posts;
};

const [criteria, setCriteria] = useState("")

const {isLoading, data: post} = useQuery(["posts", criteria], FetchPosts); //include criteria state to query key

console.log(post) 

<select
  name="filter"
  value={criteria}
  onChange={(e) => {
    setCriteria(e.target.value);  // trigger a re-render and cause the useQuery to run the query with the newly selected criteria
  }}
>
  <option>Most recent First</option>
  <option>Price: Low to High</option>
  <option>Price: High to Low</option>
</select>