The useEffect() hook helps us perform side effects within our functional components.
Let's start by understanding what are side effects.
Side effects are tasks that happen with the outside world, they refer to any actions that happen outside the normal component evaluation and render cycle. These could include sending/receiving HTTP requests/responses, and setting & managing timers.
It is important to note that these side effects are not predictable since we are performing actions outside our React components. For example, the HTTP response could fail.
The syntax for useEffect is shown below:
useEffect(() => {...},[dependencies]);
useEffect() takes two arguments -
- The first argument is a function that should be executed after every component evaluation if the specified dependencies changed. The side effect code is placed in this function.
- The second argument is a dependency array. The function in the first argument only runs if one of the dependencies in this array changed.
The dependency list is an optional argument. If no dependency array is passed, the function specified in useEffect runs during every render cycle. If an empty array is used as a dependency, the function runs only on the first render.
Let's get building 🏗️ ...
Consider the code given below to create a single-component application.
import React, { useState, useEffect } from "react";
function App() {
const [resourceType, setResource] = useState("posts");
useEffect(() => {
fetch(`https://dummyjson.com/${resourceType}`)
.then((res) => res.json())
.then((json) => console.log(json));
}, [resourceType]);
return (
<React.Fragment>
<div>
<button onClick={() => setResource("posts")}>Posts</button>
<button onClick={() => setResource("carts")}>Carts</button>
<button onClick={() => setResource("users")}>Users</button>
</div>
<h1>{resourceType}</h1>
</React.Fragment>
);
}
export default App;
The application will have 3 buttons to select a resource type. Using the resource type selected, we hit dummyJSON's /posts
, /cards
& /users
endpoints.
Since we want to dynamically change the endpoint, the fetch URL is appended with ${resourceType}
in the code. The dependency list for running the side effect contains resourceType
. Therefore, any change to the resourceType
will result in querying the appropriate endpoint and logging the result. We are essentially running a side effect each time the resourceType
changes.
On initial load, Posts
is selected since it is passed as the initial state to useState()
After clicking Carts
button.
After clicking Users
button.
Performing cleanup activities with useEffect()
We can return a function within useEffect(). This function is called before every new side effect execution and whenever the component is removed (the cleanup function does not run before the first side effect execution).
Below is an example demonstrating the cleanup functionality. (We are using the previous code with a few tweaks - no longer sending requests, and adding a return function)
import React, { useState, useEffect } from "react";
function App() {
const [resourceType, setResource] = useState("posts");
useEffect(() => {
console.log("Resouce Changed");
return () => {
console.log("Return from resource change");
}
}, [resourceType]);
return (
<React.Fragment>
<div>
<button onClick={() => setResource("posts")}>Posts</button>
<button onClick={() => setResource("carts")}>Carts</button>
<button onClick={() => setResource("users")}>Users</button>
</div>
<h1>{resourceType}</h1>
</React.Fragment>
);
}
export default App;
As you can observe from the screenshot below, on initial render, "Resource changed" is logged.
When we change our resource(clicking on the 'Carts' or 'Users' button), we observe "Return from resource change" is logged first and then "Resource Changed" is logged -->
Hence, the return code is run first and then the setup code. This happens because the return code is essentially a cleanup code.
useEffect() tends to puzzle many developers so don't beat yourself if some concepts take longer to grasp! 😄
Top comments (4)
Thanks
Glad it helped :')
Thank you @abhaysinghr1