In this tutorial we will discuss some issues with data fetching in useEffect
:
1. Race Conditions
2. No Caching
3. No content in initial HTML
4. Slow network waterfalls.
1️⃣ Race Condition
You have a component that accepts an id
as a prop, uses that id
to fetch corresponding data and display it.
I made a Sandbox . to make it more clear for you, And i also use setTimeOut()
to add random wait period.
Now, Where is the Problem ⁉
If you rapidly click the Fetch data!
button several times. The app will make several requests with different ids
which will finish randomly out of order. And as a user, I expect to see the result of the last request. but this may not be the case, our app displays a different result depending on which request completes first. Try it yourself.
For Example: Here I expect to see the result of last request which id == 58
, but the request with id == 10
finishes after the last request, So our app display its result.
How can I fix Race Conditions ⁉
To fix the race condition, we need to add a clean-up function to ignore stale responses - There are 2 main approaches:
1. Use Boolean flag.
2. Use AbortController.
⏩ Clean-up Function with Boolean Flag
According to React's official Docs:
If a component renders multiple times The previous effect is cleaned up before executing the next effect.
So, In the above code:
• Changing id
will cause a re-render.
• On every re-render the clean-up function gets run first to clean-up effects from the previous render before executing the next effect.
• ignore
is set to true
in the clean-up function, so the previous requests won't be able to update our state.
• Now, We still send a request with each click on fetch data!
button, But only the results from the last request will be used. check out the code in snadbox
⏩ Clean-up Function with AbortController
In the above code:
• We initialize a new AbortController
instance.
• Then pass the signal
from the controller to our fetch
as a signal property.
• As we did before - call the abort
function inside the clean-up function. check out the code in snadbox
✅ Using AbortController is the preferred way to cancel API requests, because it avoids wasting user bandwidth.
2️⃣ No Caching
🧐 Problem:
There is no-caching, so if the user navigate to another page and then clicks back, He will see the loading spinner again until the data is re-fetched. And this would be a bad user experience.
🤔 What we want?
When the user navigate to another page and then clicks back, He Should see the previous screen instantly instead of a spinner.
✅ Solution:
We can use third-party solution like React Query or useSwr
3️⃣ No content in initial HTML
🧐 Problem:
Fetching in useEffect
means React components render, then fetch.
In the above code Snippet:
• The function passed to useEffect
will be executed after the component renders. So this means: In the initial render the data is null.
• Then, the effect function will be executed and update state with actual data.
Since React is a Clint-Side JS library, all these renders happens on The browser. As a result the initial HTML is pretty empty. And if you try to use server-side rendering, you'll notice that useEffect
doesn't run on the server. So we will end with a big problem with SEO..
🤔 What we want?
We want to pre-render the content of a page on the server instead of on the Browser.
✅ Solution:
We can use Next.js, Next.js has Built-in server-side rendering(SSR).
4️⃣ Slow network waterfalls
🧐 Problem:
If you have parent and child components both doing fetching in useEffect
, then the child component can't even start fetching until the parent component finishes fetching. And This can lead to slow network waterfalls.
🤔 What we want?
The child component doesn’t have to wait for its parent to finish fetching their data before it can start.
✅ Solution:
Stop fetching in child component. Instead, "lift" fetch calls to a parent so they can be handled in parallel via promise.all
.
Then, pass the data down via props.
Main Resources
• https://beta.reactjs.org/learn/you-might-not-need-an-effect#fetching-data
• https://www.reddit.com/r/reactjs/comments/vi6q6f/comment/iddrjue
• https://www.youtube.com/watch?v=QQYeipc_cik
• https://maxrozen.com/race-conditions-fetching-data-react-with-useeffect
Top comments (1)
Oh many thanksss