Photo by Lautaro Andreani on Unsplash
How useEffect work?
The Effect Hook lets you perform side effects in function components
Hey everyone in this blog we are going to see how useEffect actually works. useEffect is one of the essential hooks in react.
So let's start by directly diving into the coding and understanding side by side.
First, we will create a basic app that will have three buttons, and below it will be one h1
tag that displays the dynamic output.
import { useState } from "react";
export default function App() {
const [resourceType, setResourceType] = useState("posts");
return (
<div className="App">
<button onClick={() => setResourceType("posts")}>Posts</button>
<button onClick={() => setResourceType("users")}>users</button>
<button onClick={() => setResourceType("comments")}>comments</button>
<h1>{resourceType}</h1>
</div>
);
}
(So, our app component will look like this right now. You can access csb here
Now let's see what useEffect actually does …
As explained in react documentation
The Effect Hook lets you perform side effects in function components
So here the word “side effects” is important. Side effects are basically anything that affects something outside the scope of the current function that's being executed.
For example:
- API request to backend service
- Calls to authentication service
So You must be thinking about what side effects are we going to perform in our app.
The answer to that question is this site - https://jsonplaceholder.typicode.com/
From here we will fetch respective data which in our case are posts, users, and comments.
useEffect syntax
import {useEffect} from 'react'
useEffect (()=>{
...code that you want to run
},[])
So here are few most important things about useEffect.
useEffect takes two arguments first is the callback function (an effect that you want to perform)
second argument is the dependency array. ( This is very important)
The first parameter is pretty self-explanatory. The second parameter however is a new thing.
useEffect will by default runs on every render. (So every time your counter updates or anything that causes the screen whatever effect you have written will happen). This can cause unnecessary calls or impact the performance of our app. (we have limited resources). To avoid that we use a dependency array.
Let's get back to our app now…
First, we will write a function to perform an effect. here our aim is to fetch posts. (Network call). I will use axios, default fetch web API can also be used. Since it is a network request it will be async.
async function getData(dataType) {
const response = await axios.get(
"https://jsonplaceholder.typicode.com/posts"
);
}
Now we will use useEffect without dependency array and see what happens ( can check here also)
import axios from "axios";
import { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const [resourceType, setResourceType] = useState("posts");
const [data, setData] = useState([]);
async function getData(dataType) {
const response = await axios.get(
"https://jsonplaceholder.typicode.com/posts"
);
setData(response.data);
}
useEffect(() => getData());
console.log(data);
return (
<div className="App">
<button onClick={() => setResourceType("posts")}>Posts</button>
<button onClick={() => setResourceType("users")}>users</button>
<button onClick={() => setResourceType("comments")}>comments</button>
<h1>{resourceType}</h1>
<div>
{data?.map((item) => (
<p>{item.body || item.name}</p>
))}
</div>
</div>
);
}
Now we are able to see the data on-screen and everything seems fine but, check console ones. the effect is running on every render.
Now dependency array will come to our rescue. If we want to run the side effect only once on the initial render( home-page details or username in navbar) then use an empty array as dependency and if you want to perform a side effect when specific variable changes then you will have to pass those variable in dependency array.
- With an empty array as a dependency (csb link)
import axios from "axios";
import { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const [resourceType, setResourceType] = useState("posts");
const [data, setData] = useState([]);
async function getData(dataType) {
const response = await axios.get(
"https://jsonplaceholder.typicode.com/posts"
);
setData(response.data);
}
useEffect(() => getData(), []);
console.log(data);
return (
<div className="App">
<button onClick={() => setResourceType("posts")}>Posts</button>
<button onClick={() => setResourceType("users")}>users</button>
<button onClick={() => setResourceType("comments")}>comments</button>
<h1>{resourceType}</h1>
<div>
{data?.map((item) => (
<p>{item.body || item.name}</p>
))}
</div>
</div>
);
}
Now you will side effects will run only once on the initial render. (console statement also prints only once), made our app efficient right!
- With dependency (csb link)
import axios from "axios";
import { useEffect, useState } from "react";
import "./styles.css";
export default function App() {
const [resourceType, setResourceType] = useState("posts");
const [data, setData] = useState([]);
async function getData(dataType) {
const response = await axios.get(
`https://jsonplaceholder.typicode.com/${resourceType}`
);
setData(response.data);
}
useEffect(() => getData(), [resourceType]);
console.log(data);
return (
<div className="App">
<button onClick={() => setResourceType("posts")}>Posts</button>
<button onClick={() => setResourceType("users")}>users</button>
<button onClick={() => setResourceType("comments")}>comments</button>
<h1>{resourceType}</h1>
<div>
{data?.map((item) => (
<p>{item.body || item.name}</p>
))}
</div>
</div>
);
}
So here now every time the resourceType changes, it will query the respective data, and side effects run only when the dependency value changes. ( makes our app dynamic and efficient! )
Conclusion
UseEffect is used to perform the side effect. it has three variations to use and helps achieve efficient rendering.