Lecture Notes Of Day 12:
The useEffect Hook
Objective:
Deep dive into the useEffect hook
and its uses in React applications.
Outcome:
Learn how to manage side effects
like API calls, DOM updates, or event listeners using the useEffect hook. By
the end of the class, you will understand how and when to use useEffect in
functional components to handle side effects.
1. What
is useEffect?
In React, the useEffect hook is
used to manage side effects in functional components. Side effects refer
to operations that can interact with the outside world, such as:
- Making
API calls to fetch data
- Updating
the DOM (not related to the render output)
- Setting
up or cleaning up subscriptions, timers, or event listeners
Before React hooks, managing side
effects was only possible in class components via lifecycle methods like componentDidMount,
componentDidUpdate, and componentWillUnmount. useEffect consolidates all these
into a single hook that can be used in functional components.
2. Syntax
of useEffect
The basic syntax of useEffect is:
javascript
Copy code
useEffect(()
=> {
// side effect logic here
},
[dependencies]);
- First
Argument (callback function): This is the function that
contains the code to perform the side effect. This function runs after the
component renders. The effect can also return a cleanup function
(to clean up resources when the component unmounts or when dependencies
change).
- Second
Argument (dependency array): This is an optional array
of dependencies that tells React when to re-run the effect. If you pass an
empty array [], the effect will only run once after the initial render. If
you don't pass the second argument, the effect will run after every
render.
3. How useEffect
Works
- The
effect function runs after the render and not during the render
process, which ensures that it doesn’t block the rendering of the UI.
- By
default, useEffect will run after every render. However, you can control
when it runs using the dependency array.
4.
Example: Basic Usage of useEffect
Let's see a simple example of how
useEffect is used in a functional component.
javascript
Copy code
import React,
{ useState, useEffect } from 'react';
function App()
{
const [count, setCount] = useState(0);
// This useEffect runs after every render
useEffect(() => {
console.log('Component rendered or count
changed:', count);
});
return (
<div>
<p>Count: {count}</p>
<button onClick={() =>
setCount(count + 1)}>Increment</button>
</div>
);
}
export default
App;
Explanation:
- The useEffect
hook here logs a message to the console every time the component is
rendered or when the count state changes.
- This
happens after the component renders and not during the render.
5. Using useEffect
for API Calls
A very common use of useEffect is
to fetch data from an API after a component renders.
javascript
Copy code
import React,
{ useState, useEffect } from 'react';
function App()
{
const [data, setData] = useState([]);
useEffect(() => {
// Fetch data from API
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data))
.catch(error => console.error('Error
fetching data:', error));
}, []); // Empty array means it runs once
after initial render
return (
<div>
<h1>Data:</h1>
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
}
export default
App;
Explanation:
- In
this example, useEffect makes an API call when the component mounts
(initial render).
- The
empty dependency array [] ensures that the effect only runs once, similar
to componentDidMount in class components.
6.
Cleanup in useEffect
Sometimes, you need to clean up
resources when the component unmounts or when the effect runs again. You can do
this by returning a cleanup function from useEffect.
For example, if you set up an
event listener or a timer, you might want to remove them when the component is
removed or before the effect runs again.
javascript
Copy code
import React,
{ useState, useEffect } from 'react';
function Timer()
{
const [time, setTime] = useState(0);
useEffect(() => {
const timerId = setInterval(() => {
setTime(prevTime
=> prevTime + 1);
}, 1000);
// Cleanup function to clear the timer
return () => clearInterval(timerId);
}, []); // Runs only once when the component
mounts
return (
<div>
<h1>Time: {time}s</h1>
</div>
);
}
export default
Timer;
Explanation:
- In
this example, useEffect sets up a timer that increments the time state
every second.
- The cleanup
function (clearInterval(timerId)) is returned from useEffect, ensuring
that the interval is cleared when the component unmounts, preventing
memory leaks.
7.
Dependencies in useEffect
The dependency array allows you
to control when the effect should run. If you pass variables inside the array,
the effect will only run when one of those variables changes.
javascript
Copy code
useEffect(()
=> {
console.log('Count changed:', count);
},
[count]); // Only runs when "count" changes
If you pass an empty array ([]),
the effect will run only once after the initial render. If you pass no array at
all, the effect will run after every render.
8.
Conditional Effect Execution
You can also control when an
effect should run by adding conditional logic inside the useEffect callback:
javascript
Copy code
useEffect(()
=> {
if (count > 5) {
console.log('Count is greater than 5');
}
},
[count]);
9. Best
Practices for useEffect
- Avoid
side effects that affect rendering: Keep side effects that
modify the UI outside the render logic.
- Use
clean-up functions: Always clean up timers, subscriptions, or
event listeners to avoid memory leaks.
- Keep
effects focused: Keep effects small and focused on a single
responsibility. If an effect becomes too complex, consider breaking it
into multiple useEffect calls.
- Be
mindful of dependencies: Always include all the
state and props that the effect depends on in the dependency array.
10.
Summary
- useEffect
is a hook for managing side effects in React functional components.
- It
runs after the render and can be used for operations like API calls, DOM
manipulation, event listeners, and more.
- It
can run conditionally based on dependencies and can be cleaned up to
prevent memory leaks.
- By
controlling the dependencies, you can ensure that the effect runs only
when necessary.
Assignment/Practice:
1. Create a
React app that fetches a list of users from a public API and displays them.
2. Implement
a button that changes the background color of the page when clicked. Use useEffect
to clean up any side effects.
3. Set up a
timer using useEffect that displays the time since the component was mounted.
Ensure that the timer is cleaned up when the component unmounts.
These additional assignments further explore the useEffect hook, covering aspects like cleanup, conditional rendering based on dependency changes, and error handling in API calls.
