A few days ago, I wrote an article on how to use the useState
hook. Another important hook provided by React is the useEffect
hook. Now, if you've used React Class based Components, then useEffect will help you replace functions like componentDidMount
, componentDidUpdate
, etc.
Prerequisites
- Basic knowledge of ReactJS
How to use?
useEffect takes in two arguments. A function, and an array of dependencies like so:
useEffect(function, [dependencies])
Let's start with the function argument
Function Argument
Let's use the example I used in the useState
article.
import { useState } from "react";
function App() {
const [count, setCount] = useState(1);
function incrementCount() {
setCount(count + 1);
}
return (
<div>
<h1>Hello, World</h1>
<p>{count}</p>
<button onClick={incrementCount}>Increase counter</button>
</div>
);
}
export default App;
Will give you something like this:
Now make these code:
- import { useState } from "react";
+ import { useState, useEffect } from "react";
...
const [count, setCount] = useState(1);
+ useEffect(() => {
+ console.log("useEffect running");
+ });
...
Now, go to the browser, refresh the page, open up dev tools and move to console window
Looks like it's working! But WAIT. Try clicking on the button and notice what happens:
The useEffect ran again. This is because by default, useEffect runs on every single render. When you update the state, you're basically re-rendering the component, so the useEffect runs again. This might be useful in some cases.
Replacement for componentDidMount
What if you want to run it only when the component mounts for the first time (like componentDidMount did). This is where the dependency
argument comes into play. Make this change
- useEffect(() => {
- console.log("useEffect running");
- });
+ useEffect(() => {
+ console.log("useEffect running");
+ }, []);
You're passing in an empty array of dependencies. This basically means, run the useEffect loop only on first render.
There is however still one difference between this and
componentDidMount
.useEffect(fn, [])
runs after the first render to the DOM whereascomponentDidMount
runs after "mounting" the component but before it is actually rendered(shown) in the DOM.
Run depending on a value
What if you want to run useEffect when a certain value changes. For eg. add this
const [count, setCount] = useState(1);
+ const [isDark, setIsDark] = useState(false);
...
<button onClick={incrementCount}>Increase counter</button>
+ <button onClick={() => setIsDark(!isDark)}>Toggle isDark</button>
Let's take that counter p
tag to a different component for demonstration purposes
function Counter({count}) {
return <p>{count}</p>;
}
...
<div>
<h1>Hello, World</h1>
- <p>{count}</p>
+ <Counter count={count} />
...
Now say, on the Counter
function, you want to take the isDark
prop and every time it changes we want to send out a console.log saying that the isDark
prop has changed. First let's take the prop
- <Counter count={count} />
+ <Counter count={count} isDark={isDark} />
...
- function Counter({ count }) {
+ function Counter({ count, isDark }) {
Now, if we add a useEffect hook like this:
function Counter({ count, isDark }) {
+ useEffect(() => {
+ console.log("isDark value changed")
+ }, [isDark])
Now, you will see a console.log everytime you click on the Toggle isDark
button but notice that if you click on Increase Counter
, you won't see a console.log because now the useEffect runs only when the isDark value changes and not on every render like we saw before!
So, that's it for this article. Hope you take something back from this article. There's a little more to useEffect like cleaning up functions which you can read about here.
The final code for this is as follows:
import { useState, useEffect } from "react";
function App() {
const [count, setCount] = useState(1);
const [isDark, setIsDark] = useState(false);
useEffect(() => {
console.log("useEffect running");
}, []);
function incrementCount() {
setCount(count + 1);
}
return (
<div>
<h1>Hello, World</h1>
<Counter count={count} isDark={isDark} />
<button onClick={incrementCount}>Increase counter</button>
<button onClick={() => setIsDark(!isDark)}>Toggle isDark</button>
</div>
);
}
function Counter({ count, isDark }) {
useEffect(() => {
console.log("isDark value changed");
}, [isDark]);
return <p>{count}</p>;
}
export default App;
Top comments (0)