Lesson 2. Trigger side effects with useEffect 2. Handling asynchronous effects and clean up
Not only we want to log the title two seconds after it is updated, but in the
LogTitle component itself, we also want to display the message at the same
time. This means that we have to use a local state:
const DelayedLogTitle = ({ title }) => {const [delayedTitle, setDelayedTitle] = useState('')useEffect(() => {setTimeout(() => {console.log('New title:', title)setDelayedTitle(title)}, 2000)}, [title])return <p>Logging in 2 seconds: {delayedTitle}</p>}
This will be working fine, but there might be an issue if the component is
unmounted between the time the title is updated and the time we update
delayedTitle accordingly. In that case, we would call setDelayedTitle when
the component is unmounted, and React will display a warning in the console.
To fix this issue, useEffect allows us to return a clean-up function in the
callback: this function will be executed:
- when one of the values in the dependencies array is updated, just before triggerring a new rendering,
- when the component is unmounted.
In our case we want to update the state using setDelayedTitle only if the
component is still mounted. Here, the good news is that there is a way to cancel
a timeout, giving us a first way to proceed, using clearTimeout in the clean
up function:
useEffect(() => {const timeout = setTimeout(() => {console.log('New title:', title)setDelayedTitle(title)}, 2000)return () => {clearTimeout(timeout)}}, [title])
Another way to do is to set a flag to true in the useEffect, set it to
false in the clean up function, and updating the state only if the flag is
still true. For instance, here we want to log the title in the console without
updating the state:
useEffect(() => {let active = truesetTimeout(() => {console.log('New title:', title)if (active) {setDelayedTitle(title)}}, 2000)return () => {active = false}}, [title])
This way of doing using a flag is useful when the async action cannot be
cancelled (as you can cancel a setTimeout or setInterval), for instance when
you use async functions, i.e. promises.
Now that we know how to use useEffect, let’s see how to use it to do something
very common: making HTTP requests.