React-Query: How to useQuery when button is clicked

ReactjsReact NativeReact Query

Reactjs Problem Overview


I am new to this react-query library.

I know that when I want to fetch data, with this library I can do something like this:

const fetchData = async()=>{...}

// it starts fetching data from backend with this line of code
const {status, data, error} = useQuery(myKey, fetchData());

It works. But how to trigger the data fetching only when a button is clicked? , I know I probably could do something like <Button onPress={() => {useQuery(myKey, fetchData())}}/> , but how to manage the returned data and status...

Reactjs Solutions


Solution 1 - Reactjs

According to the API Reference, you need to change the enabled option to false to disable a query from automatically running. Then you refetch manually.

// emulates axios/fetch since useQuery expectes a Promise
const emulateFetch = _ => {
  return new Promise(resolve => {
    resolve([{ data: "ok" }]);
  });
};

const handleClick = () => {
  // manually refetch
  refetch();
};

const { data, refetch } = useQuery("key", emulateFetch, {
  refetchOnWindowFocus: false,
  enabled: false // turned off by default, manual refetch is needed
});

return (
  <div>
    <button onClick={handleClick}>Click me</button>
    {JSON.stringify(data)}
  </div>
);

Working sandbox here.
 

Bonus: you can pass anything that returns a boolean to enabled. That way you could create Dependant/Serial queries.

// Get the user
const { data: user } = useQuery(['user', email], getUserByEmail)
 
// Then get the user's projects
const { isIdle, data: projects } = useQuery(
  ['projects', user.id],
  getProjectsByUser,
  {
    // `user` would be `null` at first (falsy),
    // so the query will not execute until the user exists
    enabled: user,
  }
)

Solution 2 - Reactjs

Looks like the documentation changed and is missing the manual querying section right now. Looking at the useQuery API however, you'd probably need to set enabled to false, and then use refetch to manually query when the button is pressed. You also might want to use force: true to have it query regardless of data freshness.

Solution 3 - Reactjs

You have to pass the manual: true parameter option so the query doesn't fetch on mount. Also, you should pass fetchData without the parentheses, so you pass the function reference and not the value. To call the query you use refetch().

const {status, data, error, refetch} = useQuery(myKey, fetchData, {
      manual: true,
    });

const onClick = () => { refetch() }

Refer to the manual querying section on the react-query docs for more info https://github.com/tannerlinsley/react-query#manual-querying

Solution 4 - Reactjs

There is another way to do this that also works if you want to trigger multiple refetches.

const [fetch, setFetch] = useState(null);
const query = useQuery(["endpoint", fetch], fetchData);

const refetch = () => setFetch(Date.now());

// call the refetch when handling click.

If you want to refetch multiple entities you could have a top level useState that is called for instance fetchAll and:

...
const query = useQuery(["endpoint", fetch, fetchAll], fetchData);
...

and this code will also trigger if you press a button to fetch all.

Solution 5 - Reactjs

You can try this version:

const fetchData = async()=>{...}

// it starts fetching data from backend with this line of code
const {status, data, error, refetch } = useQuery(
myKey, 
fetchData(),
{
  enabled: false,
}
);
const onClick = () => { refetch() }
// then use onClick where you need it

From documentation Doc:

enabled: boolean

  • Set this to false to disable this query from automatically running.
  • Can be used for Dependent Queries.

refetch: (options: { throwOnError: boolean, cancelRefetch: boolean }) => Promise<UseQueryResult>

  • A function to manually refetch the query.

  • If the query errors, the error will only be logged. If you want an error to be thrown, pass the throwOnError: true option

  • If cancelRefetch is true, then the current request will be cancelled before a new request is made

Solution 6 - Reactjs

At first react query gives us enabled option and by default it is true

const fetchData = async()=>{...}

const {status, data, error , refetch} = useQuery(myKey, fetchData() , {
enabled : false
}
);

<button onClick={() => refetch()}>Refetch</button>

Solution 7 - Reactjs

you can use useLazyQuery()

import React from 'react';
import { useLazyQuery } from '@apollo/client';

function DelayedQuery() {
   const [getDog, { loading, error, data }] = useLazyQuery(GET_DOG_PHOTO);

   if (loading) return <p>Loading ...</p>;
   if (error) return `Error! ${error}`;

   return (
      <div>
         {data?.dog && <img src={data.dog.displayImage} />}
         <button onClick={() => getDog({ variables: { breed: 'bulldog' } })}>Click me!</button>
      </div>
   );
}

reference: https://www.apollographql.com/docs/react/data/queries/#manual-execution-with-uselazyquery

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLeem.finView Question on Stackoverflow
Solution 1 - ReactjsNicolas HeviaView Answer on Stackoverflow
Solution 2 - ReactjsEsxielView Answer on Stackoverflow
Solution 3 - ReactjsKevin GelpesView Answer on Stackoverflow
Solution 4 - ReactjsArtur CarvalhoView Answer on Stackoverflow
Solution 5 - ReactjsVitalii AndrusishynView Answer on Stackoverflow
Solution 6 - ReactjsBuild ThoughView Answer on Stackoverflow
Solution 7 - ReactjsNaeim BordbarView Answer on Stackoverflow