Only understand this: We use useEffect to do something after the view has been rendered.
Now, let's get to code and make a simple counter to understand useEffect:
import {useState, useEffect} from 'react'
export default function App() {
const [counter, setCounter] = useState(0)
useEffect(() => {
console.log('from useEffect...', counter)
})
function incrementClickHandler() {
setCounter(counter+1)
console.log("Inside incrementClickHandler.....", counter)
}
console.log('before render...', counter)
return (
<div className='App'>
<h1>{counter} </h1>
<button onClick={incrementClickHandler}>Increment</button>
</div>
)
}
Here's the console result after the initial render (that is the increment button still not clicked):
It does not matter where the code or function is written, this will be the flow 👇:
The HTML inside the return will be rendered for the first time. However, just before the render
console.log('before render...', counter)
will run and the function inside of useEffect will run immediately after the view has been rendered. (The incrementClickHandler function will not run since we have not clicked on the increment button yet).
Here's what happens when we click the increment button for the first time:
Below 👇 is the flow when the increment button is clicked:
Step 1: While executing the HTML part, we encounter an onClick and as a result the incrementClickHandler function will be called.
Step 2: Note that there is a state update inside the incrementClickHandler function. However, the console.log following the state update is printing the previous state. This is because whenever a state is updated inside a function, the actual state update can be used only outside the function and the whole App will run again with the new state after exiting the incrementClickHandler function.
Step 3: Although the whole App is running again the useEffect and the function inside which state is updated will not be executed.
Step 4: Since the whole App is running,
console.log('before render...', counter)
will be executed.
Step 5: Now, the view will be rendered and number above the increment button will change from 0 to 1.
Step 6. Now, that the view has been rendered useEffect will run.
I explained all the above code to make you understand that the useEffect runs after the view has been rendered.
Now, you may ask: What's the point of running the function inside useState after rendering the view.
here's why? because user only cares about the view, he does not care about your console.log or localStorage (or any other side effect for that matter) that is why you should change state in the backend at last and view should reflect the state immidiately. If there is some process between state change and the render (view), then that process will always slow down the render and degrade the user experience.
Now that you have basic understanding of useEffect hook, let's understand the dependencies.
Dependency Array
The dependency array is the second optional argument in the useEffect function.
As the name implies, it is an array of dependencies that, when changed will run the function inside useEffect accordingly.
See the below picture:
Let's understand the above table by the below example:
import "./styles.css";
import { useEffect, useState } from 'react'
export default function App() {
const [resource, setResource] = useState('');
const [input, setInput] = useState('');
useEffect(() => {console.log('See The Magic')})
return (
<div className="App">
<h3>Input Element</h3>
<input onChange={e => setInput(e.target.value)}></input>
<h3>Buttons</h3>
<button onClick={() => setResource('Users')}>Users</button>
<button onClick={() => setResource('Posts')}>Posts</button>
<button onClick={() => setResource('Comments')}>Comments</button>
</div>
);
}
In the dependency array only state variables are passed and the function inside useEffect will run only when the provided state in array changes.
We'll use the above example to understand all the dependencies (array values) given in the above table.
Case 1: Array Value: No Value Passed
This is the default case and therefore the function inside useEffect will run after every render or after every state change.
useEffect(() => {console.log('See The Magic')})
Case 2: Array Value: Empty array passed
In the definition, I told you that the dependency array is the second optional argument. Therefore, for this case we'll add an empty array ([]) in useEffect and everything else remains the same.
useEffect(() => {console.log('See The Magic')}, [])
Since our array is empty and no state is passed inside it. The function inside useEffect will run only once (at the time initial render).
Case 3: Array Value: [State Variable 1]
In the definition, I told you that the dependency array is the second optional argument. Therefore, for this case we'll add an array with a single state variable in useEffect and see what happens.
useEffect(() => {console.log('See The Magic')}, [resource])
Since in our array we have passed the value resource. Therefore, The function inside useEffect will run only when the value of resource will change.
Note that the function inside useEffect is not running when we enter in the input field, although there is a state change. This is because we only passed the resource state in the dependency array.
Array Value: [State Variable 2]
Now, instead of resource state, let's pass the input state and see what happens.
useEffect(() => {console.log('See The Magic')}, [input])
As expected, function inside useEffect is not running when we clicking on the buttons. However, it is running when we type in the input box.
Since we passed input state in the dependency array, the useEffect function is dependent only on the input state.
​### Case 4: Array Value: [stateVariable1, stateVariable2]
For this case we'll pass both the state variables ([resource, input]) in useEffect and see what happens.
useEffect(() => {console.log('See The Magic')}, [resource, input])
You can see above, that useEffect is responding if any of the 2 states provided changes. However, you may notice that it's behaving exactly like the very first condition where no dependency array is passed. This is because we have only 2 states and we passed both of them in the dependency array. If we had more than 2 states, this may not be the case.
One more thing to note is that the in dependecy array only state variables are passed )(no normal variables).
That's all folks, I hope you understood useEffect.
If you have any doubt ask me in the comments section and I'll try to answer as soon as possible.
I write one articles related to web-development (mainly react).
If you love the article follow me on Twitter: @therajatg
If you are the Linkedin type, let's connect: https://www.linkedin.com/in/therajatg/
Have an awesome day ahead 😀!
Originally published at https://rajatgupta.net/useeffect-in-react-everything-you-need-to-know
Top comments (2)
Hey I really liked this post, thanks for sharing! I find this very helpful in understanding useEffect in React! Thanks!
Thanks for the appreciation man!