React useEffect Hook

React UseEffect Hook

Side effects

Data fetching, setting up a subscription, and manually changing the DOM in React components are all examples of side effects. Whether or not you’re used to calling these operations “side effects”

useEffect

  • The Effect Hook lets you perform side effects in functional components
  • Signature is useEffect(fn, [])
  • It is a close replacement for componentDidMount, componentDidUpdate and componentWillUnmount.
  • The second parameter is dependency list. If given dependency list, useEffect hook only executes when dependency changes. This improves performance.
  • If dependency list is an empty array, then useEffect is only called once at initial render
  • you can have multiple useEffect functions defined in a component, each with a differnt dependency
  • To Clean up, add the clean up function in the return statement in the useEffect hook

Component Mount

If you pass an empty array ([]) as second parameter, the props and state inside the effect will always have their initial values. This is equivalent to componentDidMount lifecycle method.

Todo.js - fetch data when component mounts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React, {useEffect} from 'react'

function Todo() {
const [todoid, setTodoid] = useState(1);
const [todo, setTodo] = useState({});

useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1" )
.then( res => res.json())
.then(res => setTodo(res))
.catch(err => console.log(err));
}, [])


return (
<>
{todo.title}
</>
)
}

useEffect do not take an async function that returns a promise. If you need to use async function, write the async function inside the effect and call it immediately.

1
2
3
4
5
6
7
8
9
useEffect(() => {
async function fetchData (){
const response = await fetch("https://jsonplaceholder.typicode.com/todos/1")
const json = await response.json()
setTodo(json)
console.log(json)
}
fetchData()
}, [])

With Dependency List

dependency list can contain props or state. Whenever the dependency changes, the useEffect function gets called.

Example: when the state todoid change, fetch the data from API endpoint

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Todo() {
const [todoid, setTodoid] = useState(1);
const [todo, setTodo] = useState({});

useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/" + todoid)
.then( res => res.json())
.then(res => setTodo(res))
.catch(err => console.log(err));
}, [todoid])


return (
<>
<input type="text" value={todoid} onChange={(e) => setTodoid(e.target.value)} />
{todo.title}
</>
)
}

Clean up

  • React performs the cleanup when the component unmounts.
  • useEffect keeps the side effect code together
  • The returned function from useEffect function call is invoke when cleaning up.

Here is the example from Hooks doc - clean up function will get called when the component unmounts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import React, { useState, useEffect } from 'react';

function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);

useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// Specify how to clean up after this effect:
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});

if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}

Reference