React 16.6 has added a <Suspense> component that lets you wait for some code to load and declaratively specify a loading state (like a spinner) while the data is still being fetched.
_Suspense _lets your components wait for something(data) before they can render.
A common way to fetch data in React apps today is to use an effect, like this:
// In a function component:
useEffect(() => {
fetchSomething();
}, []);
This approach is called fetch-on-render since it does not start fetching until after the component has rendered on screen, this approach normally leads async waterfall.
Let's take a look on a component fetching data with the traditional way, consider the components, and :
function Student() {
const [student, setStudent] = useState(null);
useEffect(() => {
getStudent().then(s => setStudent(s));
}, []);
if (student === null) {
return <p>Loading, please wait...</p>;
}
return (
<>
<h1>{student.name}</h1>
<Text>{student.name} Subjects</Text>
<StudentSubjects />
</>
);
}
function StudentSubjects() {
const [subjects, setSubjects] = useState(null);
useEffect(() => {
getStudentSubjects().then(ss => setSubjects(ss));
}, []);
if (subjects === null) {
return <h2>Loading, please wait...</h2>;
}
return (
<ul>
{subjects.map(subject => (
<li key={subject.id}>{subject.name}</li>
))}
</ul>
);
}
What's happening here is:
- We start fetching a student
- We wait…
- We finish fetching student
- We start fetching student subjects
- We wait…
- We finish fetching student subjects
If fetching a student takes three seconds, we’ll only start fetching the student subjects after three seconds! Remember our old friend, waterfall? That’s a waterfall right there: an unintentional sequence that should have been parallelized.
Waterfalls are common in code that fetches data on render. They’re possible to solve, but as the product grows, many people prefer to use a solution that guards against this problem.
Now, let's see how we can improve this by using :
// This is not a Promise. It's a special object from the Suspense integration.
const resource = fetchProfileData();
function StudentDetails() {
return (
<Suspense fallback={<h1>Loading student...</h1>}>
<Student />
<Suspense fallback={<h1>Loading student subjects...</h1>}>
<StudentSubjects/>
</Suspense>
</Suspense>
);
}
function Student() {
// Try to read student info, although it might not have loaded yet
const student = resource.student.read();
return <h1>{student.name}</h1>;
}
function StudentSubjects() {
// attempt to read student subjects, although they might not have loaded yet
const subjects = resource.subjects.read();
return (
<ul>
{subjects.map(subject => (
<li key={subject.id}>{subject.name}</li>
))}
</ul>
);
}
With Suspense, here's what happens:
- Start fetching
- Start rendering
- Finish fetching
In the traditional approach here's what was happening:
- Start fetching
- Finish fetching
- Start rendering We fetched data before we called setState.
With Suspense, we don’t wait for the response to come back before we start rendering on screen. We start rendering immediately after kicking off the network request.
On the Suspense component, the fallback is basically what is displayed while still loading, a spinner, maybe.
Thank you very much for reading.
Happy coding!🤓😎
Top comments (0)