1

TL;DR: Why can't I use "key_one" in both cases?

When a request fails, it causes weird behavior in the following situation: Parent component and child component use the same query key.

Is there something I've missed? If I use different keys "key_one" and "key_two", my app fails gracefully. If I use the same key, my app falls into a loop. In the working example I've used 'key_one' and 'key_two'. This is not optimal, as in normal circumstances I want them to be the same for caching reasons.

Intended result: enter image description here

Working code:

async function doFetch() {
  throw new Error("Network response was not ok");
}

function MyInnerComp() {
  const { isError, error } = useQuery("key_one", doFetch);

  return (
    <div style={{ border: "1px solid", padding: "10px" }}>
      <h2>Hello from inner component!</h2>
      {isError && <div>Error! {error.message}</div>}
    </div>
  );
}

function Comp() {
  const { isLoading, isError, error } = useQuery("key_two", doFetch);

  if (isLoading) return <div>loading</div>;

  return (
    <div style={{ border: "1px solid", padding: "10px" }}>
      <h2>Parent component.</h2>
      {isError && <div>Error! {error.message}</div>}
      <hr />
      <div>lorem ipsums</div>
      <MyInnerComp />
    </div>
  );
}

Codesandbox: https://codesandbox.io/s/dry-waterfall-21q741?file=/src/index.js

2 Answers 2

2
  1. At the very start Comp render and no data has been fetched => useQuery start fetch and isLoading is updated to true
  2. isLoading = true => Comp then render <div>loading</div>
  3. Data is fetched => isLoading = false
  4. isLoading = false => Comp render <div>...<MyInnerComp /></div>
  5. MyInnerComp render => useQuery of MyInnerComp trigger a refetch (as it was rendered after the query was done) => update isLoading to true
  6. => Comp render again due to isLoading (of the same key) being updated => it render loading and MyInnerComp is unmounted
  7. ... infinite loop that trigger query again and again (MyInnerComp will be mounted again like a fresh new component which retrigger useQuery)

In case you use different key, when MyInnerComp render, it does not update isLoading of key_one which does not trigger the loop

If I'm not wrong a solution might be to use isFetched:

function Comp() {
  const { isLoading, isFetched } = useQuery("key_one", doFetch);

  if (isLoading && !isFetched) return <div>loading</div>;

  return (
    <div style={{ border: "1px solid", padding: "10px" }}>
      <h2>Parent component.</h2>
      {isError && <div>Error! {error.message}</div>}
      <hr />
      <div>lorem ipsums</div>
      <MyInnerComp />
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

1 Comment

This was a very valuable insight! I didn't realize that react query would trigger isLoading=true everywhere else in the app too. In hindsight it seems obvious.
0

Instead of doing another query you could try to pass it as props / use it directly. Use the error and isLoading directly in the other component

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.