preamble
There are times when we want toAfter getting the data from the server
And then to render a component, in order to achieve this effect we currently have several implementations:
-
Put the data request to the parent component to do it and use the
v-if
The control gets the child component before rendering it, and then passes the data from the parent component through theprops
Passed to the subcomponent. -
In the subcomponent's
onMounted
and request the data using thev-if
In the subcomponent'stemplate
The outermost layer is controlled and only renders the content in the subcomponent when it gets the data.
Both of the above options have their own drawbacks and are not perfect. The ideal solution would be to put the logic for fetching data from the server in a subcomponent, and during the fetching period let the subcomponent"Pause."
For a moment, don't render until the data request is complete and then go ahead and render the subcomponent for the first time.
Ouyang wrote an open source ebookvue3 Compilation Principles Revealed, reading this book can give you a qualitative improvement in your knowledge of vue compilation. This book is accessible to beginner and intermediate front-ends and is completely free, just asking for a STAR.
The perfect solution
The disadvantage of the first approach is that although the child component gets the data before it starts rendering, the logic of the data request is put on top of the parent component, and we expect all the logic to be encapsulated inside the child component.
The disadvantage of the second approach is that it actually renders the subcomponent once on initialization, when we haven't got the data from the server yet. That's why we have to use thev-if
existtemplate
The outermost control of the subcomponent is not rendered at this time. When you get the data from the server and then render the subcomponent a second time, only then will the content in the subcomponent be rendered to the page.This method obviously subcomponents are rendered 2 times.
So is there a perfect solution where the logic to fetch the data from the server is placed in a subcomponent and during the fetching of the data the subcomponent is allowed to"Pause."
What about one, not rendering it first and waiting until the data request is complete before going to render the subcomponent for the first time?
The answer is: of course you can, vue3'sSuspense component
+Use await at the top of setup to fetch data
It would be perfect for this!!!!
Two imperfect examples
To give you a better visualization of the oxymoron of the perfect solution, let's take a look at the two less-than-perfect examples we talked about earlier.
Example of requesting data in a parent component
The following is an example of requesting data in a parent component with the following code:
<template>
<ChildDemo v-if="user" :user="user" />
<div v-else>
<p>loading...</p>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import ChildDemo from "./";
const user = ref(null);
async function fetchUser() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: "John Doe",
phone: "13800138000",
});
}, 2000);
});
}
onMounted(async () => {
= await fetchUser();
});
</script>
The code for the subcomponent is as follows:
<template>
<div>
<p>user ID:{{ }}</p>
<p>cell phone number:{{ }}</p>
</div>
</template>
<script setup lang="ts">
const props = defineProps(["user"]);
</script>
For this scenario we will get from the server sideuser
logic is all placed in the parent component, and using theprops
commander-in-chief (military)user
Passed to the subcomponent and displays a loading copy during the data retrieval from the server.
This accomplishes what we need but puts the subcomponent in the position of getting theuser
logic into the parent component, we expect to encapsulate all of this logic in the child component, so this solution is not perfect.
Example of a subcomponent requesting data in onMounted
Let's take a look at the second option, the parent component code code is as follows:
<template>
<ChildDemo />
</template>
<script setup lang="ts">
import ChildDemo from "./";
</script>
The subcomponent code is as follows:
<template>
<div v-if="user">
<p>user ID:{{ }}</p>
<p>cell phone number:{{ }}</p>
</div>
<div v-else>
<p>loading...</p>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
const user = ref(null);
async function fetchUser() {
// utilizationsetTimeoutSimulate getting data from the server
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: "John Doe",
phone: "13800138000",
});
}, 2000);
});
}
onMounted(async () => {
= await fetchUser();
});
</script>
We put the data request in theonMounted
in which initialization goes to the first rendering of the subcomponent. At this pointuser
The value of thenull
, so we had to do it intemplate
The outermost layer of thev-if="user"
Controls the content of the subcomponent not to be displayed at this time, in thev-else
in to render loading copy.
When the data is gotten from the server and given to the responsive variableuser
Re-assigning the value triggers a re-rendering of the page, at which point a second rendering is performed before the content of the sub-component is rendered to the page.
As you can see from the above this solution the subcomponent is obviously rendered twice, and we also write the loaded display logic inside the subcomponent, which increases the complexity of the subcomponent code. So this solution is not perfect.
The perfect scenario would be in thefetchUser
Letting subcomponents during"Pause" rendering
,fallback
to render a loading page. And this loading display logic doesn't need to be encapsulated in a subcomponent, it's in the"Pause" rendering
period of timeautomation
It will be able to display it. Wait until the request for data from the server is complete before you start rendering the subcomponents and automatically unload the loading page.
Suspense + await implements the perfect example
Here's the official website for theSuspense
The presentation:
<Suspense>
is a built-in component to coordinate the handling of asynchronous dependencies in the component tree. It allows us to wait for multiple nested asynchronous dependencies at the upper level of the component tree to finish resolving at the lower level, and can render a loaded state while waiting.
What it means isSuspense
component can listen to the following asynchronous subcomponent and go ahead and render a loading page before waiting for the asynchronous subcomponent to finish rendering.
Suspense
The component supports two slots:#default
cap (a poem)#fallback
. If#default
slot has an asynchronous component, then it goes ahead and renders the#fallback
in the#fallback
in the page to be taken out, instead rendering the content of the asynchronous component to the page.
If our subcomponent is an asynchronous component, then theSuspense
Not just to help us realize the function we want aca.
Suspense
can be used during the loading of asynchronous subcomponents with the#fallback
The slot automatically renders a loading loading for us, and waits until the asynchronous subcomponent is loaded before it goes to render the content in the subcomponent for the first time.
So now the question is how do we make our subcomponent an asynchronous subcomponent?
The answer to this question is actually told on the vue website, if a component's<script setup>
The top layer uses theawait
Then the component becomes an asynchronous component. All we need to do is to use await at the top level of the subcomponent to request data from the server.
Parent component of the perfect solution
Here's an example of how to use theSuspense
The code of the modified parent component, is as follows:
<template>
<Suspense>
<AsyncChildDemo />
<template #fallback>loading...</template>
</Suspense>
</template>
<script setup lang="ts">
import AsyncChildDemo from "./";
</script>
in the parent component using theSuspense
component, 2 slots are passed to this component.#default
Slots are asynchronous subcomponentsAsyncChildDemo
The default slots can be used without adding the#default
。
And with the use of#fallback
slot, the asynchronous subcomponent will not be rendered for a while while the asynchronous subcomponent is being loaded.AsyncChildDemo
. Change to render first#fallback
The loading in the slot will automatically replace the loading with the content in the subcomponent when the asynchronous subcomponent finishes loading.
Subcomponents of the Perfect Solution
Here's one that uses theawait
The modified subcomponent code, is as follows:
<template>
<div>
<p>user ID:{{ }}</p>
<p>cell phone number:{{ }}</p>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
const user = ref(null);
= await fetchUser();
async function fetchUser() {
// utilizationsetTimeoutSimulate getting data from the server
return new Promise((resolve) => {
setTimeout(() => {
resolve({
name: "John Doe",
phone: "13800138000",
});
}, 2000);
});
}
</script>
We are in<script setup>
The top level uses theawait
and then theawait
The value you get is assigned to theuser
Variables. The top level uses theawait
After that the subcomponent becomes an asynchronous component and waits until theawait fetchUser()
After the execution, that is, after getting the data from the server, the subcomponent is considered loaded.
And since we're using theSuspense
This is why you don't render the subcomponent until it's loaded, i.e. until you get the data from the server (the equivalent of "pausing" the rendering of the subcomponent). Instead, it renders#fallback
The loading in the slot waits until the asynchronous subcomponent is loaded after getting the data from the server. Only then will the subcomponent be rendered for the first time, and the loading will be replaced with the content rendered by the subcomponent.
Because the first rendering of the subcomponent already got theuser
value, at which point theuser
No longer.null
so we don't have to use it at the top level of the template.v-if="user"
Although there is a go read in the template。
go throughParent component Suspense + child component top-level await
After the modification of the rendering parent component'sSuspense
When it finds out that its subcomponent has an asynchronous component, it will "pause" the rendering of the subcomponent and automatically render the loading component instead.
Subcomponents in thesetup
top level usageawait
Wait for the data request from the server, when the data from the server to get the sub-component at this time is considered to be loaded, then the first rendering will be carried out, and automatically replace the content of the loading for the sub-component in the rendered content.
besidesSuspense
It also supports several asynchronous sub-components to fetch data from the server, and will automatically replace the loading with the content rendered by these asynchronous sub-components only after these sub-components have fetched the data from the server.
there's alsoSuspense
The component is still currentlyexperimental
features, production environments need to be used with caution.
Take a quick look.Suspense
How do I "pause" rendering?
Suspense
When rendering a subcomponent, the render function of the asynchronous subcomponent will not be executed immediately when the subcomponent is found to be an asynchronous component. Instead, it will add a function calleddeps
that identifies the current default subcomponent as an asynchronous component.Pause Rendering
Asynchronous subcomponents.
Since the asynchronous subcomponent is aPromise
, so it is possible to load asynchronous subcomponents in thePromise
followed by the addition of.then()
method in the.then()
method before going on to render the asynchronous subcomponent.
Currently the asynchronous subcomponent has paused rendering, and will then go and read thedeps
Marker. If thedeps
mark sth. astrue
, indicating that the asynchronous subcomponent has paused rendering, at which point it will go ahead and move thefallback
The loading component in the slot renders to the page.
It is triggered when the asynchronous subcomponent has finished loading thePromise
(used form a nominal expression).then()
method, thusContinue rendering.
Asynchronous subcomponents. In the.then()
method will execute the render function of the asynchronous subcomponent to generate the virtual DOM, and then generate the real DOM based on the virtual DOM.fallback
The content in the slot is replaced with the content in the real DOM generated by the asynchronous component.
Here's the flowchart I drew (The flowchart is followed by a summary at the end of the article):
summarize
In this post we talked about how there are scenarios that need to beAfter getting the data from the server
to render a component again, at which point we can use theParent component Suspense + child component top-level await
of the perfect program.
When rendering the parent component'sSuspense
When a component finds that its children have asynchronous components, it "pauses" rendering the children and automatically renders the loading component instead.
Subcomponents in thesetup
top level usageawait
Wait for the data request from the server, when the data from the server to get the sub-component at this time is considered to be loaded, then the first rendering will be carried out, and automatically replace the content of the loading for the sub-component in the rendered content.
besidesSuspense
It also supports several asynchronous sub-components to fetch data from the server, and will automatically replace the loading with the content rendered by these asynchronous sub-components only after these sub-components have fetched the data from the server.
endSuspense
The component is still currentlyexperimental
features, production environments need to be used with caution.
Follow the public number: [Front-end Ouyang], give yourself a chance to advance vue
Also Ouyang wrote an open source ebookvue3 Compilation Principles Revealed, reading this book can give you a qualitative improvement in your knowledge of vue compilation. This book is accessible to beginner and intermediate front-ends and is completely free, just asking for a STAR.