React 01 - Source Code, Mechanism of Suspense and unstable_createResource
Everyone seems very excited about this feature. Even in interviews, they would like to ask whether you have tried this feature, whether you know about the mechanism. While most people use them in daily development, few knows how is it implemented. So today, we will analyze the source code and dive deep in this feature.
Mainly, we will discuss 3 parts:
- i. Suspense Use Cases
- ii. Source Code and Mechanism
- iii. Data Fetching and
unstable_createResource
?
i. Suspense Use Cases
If we look at the official document of React, we can see Suspense mainly can be used in 2 places:
For code split, it is quite simple. Using React.lazy
with Suspense
, we can quickly split our code, without too much code refactor.
You can see the results in Code Split with Webpack and Suspense in React .
For data fetching, we will talk about it later.
ii. Source Code and Mechanism
So why this simple change ( lazy
and Suspense
) makes code split happen? Let’s see the official explanation of Suspense
:
- In the
render
method, read a value from thecache
- If the value is already cached, the
render
continues like normal - If the value is not already cached, the cache
throw a promise
- When the
promise resolves
, React retries where it left off
Quite simple, right? So we can draw a conclusion:
lazy
is some kind of a cache, it turns a normal import component into a cacheable component (lazyComponent
)Suspense
implements reading from the cache, wait and retries where it left off
With this in mind, let’s see the source code.
1. read a value from the cache
let Component = readLazyComponentType(elementType);
2 && 3. If the value is already cached, the render
continues like normal && If the value is not already cached, the cache throw a promise
The throw promise is to fetch the cache content. Then how to fetch them? Use ctor
:
When is ctor
passed to lazyComponent
?
When we use lazy
to import a component, the import
itself is a Thenable
class.
So where is 4. When the promise resolves
, React retries where it left off?
Let’s implement one! Since lazyComponent
will throw error if no cache found, so we catch them (in componentDidCatch
) , wait them to resolve and retry:
And use it to replace Suspense
:
Run it:
cd webpack_Learn
npm i
npm run-script start_server
npm start
Wow, it works~
iii. Data Fetching and unstable_createResource
In i Suspense Use Cases, we talked about 2 aspects:
- Code Split
- Data Fetching
But we don’t give explanation or examples of data fetching. Why? Because it is complicated, and even React
itself are experimenting them. It brings revolution to the relationship between fetch and render.
- Fetch-on-render (for example, fetch in useEffect): Start rendering components. Each of these components may trigger data fetching in their effects and lifecycle methods. This approach often leads to “waterfalls”.
- Fetch-then-render (for example, Relay without Suspense): Start fetching all the data for the next screen as early as possible. When the data is ready, render the new screen. We can’t do anything until the data arrives.
- Render-as-you-fetch (for example, Relay with Suspense): Start fetching all the required data for the next screen as early as possible, and start rendering the new screen immediately — before we get a network response. As data streams in, React retries rendering components that still need data until they’re all ready.
With suspense
, now we Render-as-you-fetch. In React Official Document and other blogs, they mainly use react-cache
for demos. But react-cache
is unstable, as we can see form the method name — unstable_createResource
and it is incompatible with latest React
. However, we shall still see the source code and try to implement a simple one ourselves!
The mainly usage is below.
And the source code ReactCache.js
:
As we read from resource, if not cached, throw a promise, and Suspense
then can catch it, wait it and retry.
OK, since react-cache
is not compatible with latest React
, we create a simple one! Keep these 2 key points in mind as we had saw in previous section:
- If the value is already cached, the
render
continues like normal (return the cache resource) - If the value is not already cached, the cache
throw a promise
(throw a promise)
Try to use them:
cd webpack_Learn
npm i
npm run-script start_server
npm start
Yeah! We did it! And as we can see, all resources are loaded only once!
Where is the code:
cd webpack_Learn
npm i
npm run-script start_server
npm start
Reference
What is this place? Dali Ancient City, Dali, Yunnan, China