Demystifying useEffect, why did it render?

What is useEffect?

The Effect Hook lets you perform side effects in function components:

import React, { useState, useEffect } from 'react';function Example() {
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

This snippet is based on the counter example from the previous page, but we added a new feature to it: we set the document title to a custom message including the number of clicks.

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” (or just “effects”), you’ve likely performed them in your components before.

How to prevent Infinite rendering

import {useState, useEffect} from "react";

const App = () => {
const [user, setUser] = useState(null)
console.log('Rendering App');

useEffect(() => {
console.log('Running useEffect');
fetch('<https://jsonplaceholder.typicode.com/users/1>')
.then(response => response.json())
.then(json => setUser(json))
})

return (
<div>
{user ?
<>
<pre>{JSON.stringify(user)}</pre>
</>
:
<p>User unknown</p>
}

</div>
);
}

export default App;

Let’s have a look and see how our code gets executed.

The default behaviour for effects is to fire the effect after every completed render. That way an effect is always recreated if one of its dependencies changes.

To implement this, pass a second argument to useEffect that is the array of values that the effect depends on. Our updated example now looks like this:

import {useState, useEffect} from "react";

const App = () => {
const [user, setUser] = useState(null)
console.log('Rendering App');

useEffect(() => {
console.log('Running useEffect');
fetch('<https://jsonplaceholder.typicode.com/users/1>')
.then(response => response.json())
.then(json => setUser(json))
}, [user])

return (
<div>
{user ?
<>
<pre>{JSON.stringify(user)}</pre>
</>
:
<p>User unknown</p>
}

</div>
);
}

export default App;

Terminology:

Explanation

How can we fix this?

import {useState, useEffect, useRef} from "react";

const App = () => {
const [user, setUser] = useState(null)
console.log('Rendering App');

useEffect(() => {
console.log('Running useEffect');
fetch('<https://jsonplaceholder.typicode.com/users/1>')
.then(response => response.json())
.then(json => {
setUser(JSON.stringify(json))
})
}, [user])

return (
<div>
{user ?
<>
<pre>{user}</pre>
</>
:
<p>User unknown</p>
}

</div>
);
}

export default App;

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store