I am following the tutorial of Relay and it is Step 3, as on https://relay.dev/docs/tutorial/queries-1/. The code with my debugging, is
export default function Newsfeed() {
console.log("HERE 0")
const data = useLazyLoadQuery(
NewsfeedQuery,
{}
)
console.log("HERE 1", JSON.stringify(data));
and in the Google Chrome's dev console, I am able to see the following:
So it is very strange: it looks like it is able to reach the "HERE 0", and then fetch data, as if it is blocking I/O (network fetch) (the term blocking I/O means, like in the old days, when we do a Unix system call read()
, this function will never return until it has finished the reading task, unlike nowadays, we do a JavaScript fetch()
and set up a then
handler and fetch()
immediately returns without reading a single byte from the network), and then cause a re-render of the component again: note that it didn't go to "HERE 1", but did a "HERE 0" again, and then "HERE 1".
This is very different from what React works like. Traditional React app is like,
const [data, setData] = useState(null);
useEffect(() => {
// fetching data here
}, []);
return (
<div>{
data && ... // display the data
}</div>
);
that is, it will go to the end of function and does not show anything, because data
is null. Once data
is something caused by the setData
, which causes a re-render, then the component will show something. So it is a running to the completion of the function TWICE.
The useLazyLoadQuery()
code above does not look like a "run to completion TWICE". It looks like it magically can cause a re-render in the middle.
In fact it doesn't look like it is "lazy". It looks like it is diligently working (how the blocking I/O was in the old days).
How does it work?
This is because Relay uses Suspense. From tutorial you linked:
When using Suspense for data fetch (either throwing promises or using new
use
hook), React will stop rendering ('suspend') component if it requires some data which isn't here yet. React will showfallback
of nearest Suspense boundary and re-render subtree when data is loaded.In your case
useLazyLoadQuery
requests some data under the hood and Next.js handles all Suspense-related stuff, so this might be less noticeable. But if you'd try to useuseLazyLoadQuery
in plain React project (i.e. without frameworks), you probably will get error from React as it was unable to find Suspense boundary, unless you explicitly define one.I did a bit of digging about all things Suspense and wrote an article some time ago. If you're interested in how Suspense works it might be good starting point.