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.
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
CodePudding user response:
- At the very start Comp render and no data has been fetched => useQuery start fetch and isLoading is updated to true
- isLoading = true => Comp then render
<div>loading</div>
- Data is fetched => isLoading = false
- isLoading = false => Comp render
<div>...<MyInnerComp /></div>
- MyInnerComp render => useQuery of MyInnerComp trigger a refetch (as it was rendered after the query was done) => update isLoading to true
- => Comp render again due to isLoading (of the same key) being updated => it render loading and
MyInnerComp
is unmounted - ... 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>
);
}
CodePudding user response:
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