1. Why is the return a function? return () => { ignore = true };
From the docs:
Why did we return a function from our effect? This is the optional cleanup mechanism for effects. Every effect may return a function that cleans up after it. This lets us keep the logic for adding and removing subscriptions close to each other. They’re part of the same effect!
and
When exactly does React clean up an effect? React performs the cleanup when the component unmounts. However, as we learned earlier, effects run for every render and not just once. This is why React also cleans up effects from the previous render before running the effects next time. We’ll discuss why this helps avoid bugs and how to opt out of this behaviour in case it creates performance issues later below.
2. What is ignored used for in this example?
Initially in useEffect Hook ignore is set like, let ignore = false;.
When fetchProduct function executes it checks for ignore is true and accordingly sets setProduct(json).
This means we have state called product and setting the value in state using setProduct(json).
This product in state is used to render details on page.
Note: As [productId] is passed as second argument to useEffect, fetchProduct function will only get executes when productId changes.
See optimizing performance by skipping effects.
Answer from ravibagul91 on Stack OverflowVideos
1. Why is the return a function? return () => { ignore = true };
From the docs:
Why did we return a function from our effect? This is the optional cleanup mechanism for effects. Every effect may return a function that cleans up after it. This lets us keep the logic for adding and removing subscriptions close to each other. They’re part of the same effect!
and
When exactly does React clean up an effect? React performs the cleanup when the component unmounts. However, as we learned earlier, effects run for every render and not just once. This is why React also cleans up effects from the previous render before running the effects next time. We’ll discuss why this helps avoid bugs and how to opt out of this behaviour in case it creates performance issues later below.
2. What is ignored used for in this example?
Initially in useEffect Hook ignore is set like, let ignore = false;.
When fetchProduct function executes it checks for ignore is true and accordingly sets setProduct(json).
This means we have state called product and setting the value in state using setProduct(json).
This product in state is used to render details on page.
Note: As [productId] is passed as second argument to useEffect, fetchProduct function will only get executes when productId changes.
See optimizing performance by skipping effects.
I will explain it here, as it took me a while to understand the explanations above, so I will try to make it simpler for others. Answers to your questions:
Why is return a function?
return () => { ignore = true };
useEffect offers the return function which is used for cleanup purposes. OK!, When do you need a cleanup? If You subscribe to something (like an event listener) and want to unsubscribe from it, this is where You should add the unsubscription logic to prevent a race condition or other issues!
What is ignore used for in this example?
ignore is used as a flag that tells your effect to ignore, or not, the API call. When is that used? When a race condition might occur.
Example of a race condition:
Imagine You have a list of products, and You fetch product details when a product is clicked. If You click on products quickly, multiple API calls might be in progress simultaneously, resulting in changes to product_id that would trigger useEffect to run multiple times. Here's what could happen:
- Click on
product1: an API call forproduct1will trigger. - Quickly click on
product2: triggers API call forproduct2. - API call for
product2finishes first and the page updates withproduct2data - API call for
product1finishes later, and the page updates withproduct1data.
Now data for product1 is displayed on the page, even though product2 was clicked last. This is a race condition.
BUT WHAT DOES THAT HAVE TO DO WITH ignore??
Logic explanation
ignore, my dear, tells setProduct to ignore the data from product1, and to not update the state with It, or in other words, It is used to ensure outdated API calls don't update the state when a race condition occurs.
Code explanation
First scenario : No race condition
- Click on
product1:ignore = false- call API for
product1 - Data arrives
If (!ignore) = true-> update state withproduct1data- Set
ignore = trueinside cleanup function. - Congrats!
product1data is displayed correctly.
Second scenario: Race condition
product1is clickedignore = false- call API for
product1 - data still hasn't arrived
- Quickly click on
product2ignore = false- call API for
product2
- Data for
product2arrives first!ignoreistrue-> update state withproduct2data- Cleanup function sets
ignore = true
- Data for
product1arrives laterif (!ignore) = false(becauseignore = true)- Oops, old data is ignored, so
product1data does not update the state.
And this is how we will always have up-to-date data.