skip to Main Content

we use useQuery hook in the following way

function Dogs({ onDogSelected }) {
  const { loading, error, data } = useQuery(GET_DOGS);

  if (loading) return 'Loading...';
  if (error) return `Error! ${error.message}`;

  return (
    <select name='dog' onChange={onDogSelected}>
      {data.dogs.map((dog) => (
        <option key={dog.id} value={dog.breed}>
          {dog.breed}
        </option>
      ))}
    </select>
  );
}

here we are using destructuring assignment syntax and defining a const variable loading and assigning it to the loading property of the useQuery result object. But as loading is of boolean type, hence this variable is assigned according to pass by value, then how this variable changes to false as initially it is true. As the variable is const, so this value should not change. I am not able to understand what happens behind the scenes when useQuery is used?

2

Answers


  1. But as loading is of boolean type, hence this variable is assigned according to pass by value, then how this variable changes to false as initially it is true.

    It doesn’t. The loading const you get during the first call to your component function never changes. But later, when the ajax call finishes, useQuery updates a state member, which makes React call your component function again to re-render. In that call, useQuery returns a new value for the new loading const that’s specific to that function call. This is just like useState, which always returns the up-to-date state value.

    in useState we set the state explicitly to a new value and it triggers re-rendering of the component but here we are not doing anything except calling it once so how does it triggers the re-render ?

    That happens because useQuery is using and updating state members in its code, ones you only see indirectly via its return value. Since you’re calling it during the render call to your component function, those state members are stored in your component instance’s state data, so updating them makes your component re-render.

    Let’s mock it up with our own stand-in for useQuery that just waits a moment then returns a random number, so we can see the code doing what the code "hidden" away in useQuery is doing (it’s not really hidden, it’s open source, but…):

    const { useState, useEffect } = React;
    
    function useDelayedRandom() {
        console.log(`useDelayedRandom: called`);
    
        const [rand, setRand] = useState(null);
    
        useEffect(() => {
            console.log(`useDelayedRandom: scheduling timer`);
            const timer = setTimeout(() => {
                const rand = Math.floor(Math.random() * 10000);
                console.log(`useDelayedRandom: setting rand = ${rand}`);
                setRand(rand);
            }, 1000);
            return () => clearTimeout(timer);
        }, []);
    
        return rand
    }
    
    const Example = () => {
        console.log(`Example: called`);
    
        const rand = useDelayedRandom();
    
        console.log(`Example: rand = ${rand}`);
        
        return (
            <div>rand = { rand }</div>
        );
    };
    
    const root = ReactDOM.createRoot(document.getElementById("root"));
    root.render(<Example />);
    <div id="root"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>

    The useDelayedRandom hook waits a second, then generates a random number and does a state update (setRand(rand)). That state is held in your component instance (behind the scenes in React’s internals), so updating it schedules the re-render.

    useQuery is doing much the same, but updating in response to the ajax call completing rather than a timer.

    Login or Signup to reply.
  2. The React Query docs at tanstack.com/query/latest/docs/framework/react/overview should answer this. Your <Dogs> component is (or should be) wrapped in a <QueryClientProvider>. I believe this outer <QueryClientProvider> is responsible for rerendering your <Dogs> component until useQuery() returns data.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search