DEV Community

Kavin Desi Valli
Kavin Desi Valli

Posted on • Originally published at livecode247.com on

Beginner's guide to useEffect hook in React

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])

Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

Will give you something like this: Starting App

Now make these code:

- import { useState } from "react";
+ import { useState, useEffect } from "react";
...
    const [count, setCount] = useState(1);
+ useEffect(() => {
+ console.log("useEffect running");
+ });
...

Enter fullscreen mode Exit fullscreen mode

Now, go to the browser, refresh the page, open up dev tools and move to console window

useEffect first

Looks like it's working! But WAIT. Try clicking on the button and notice what happens:

useEffect on re-render

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");
+ }, []);

Enter fullscreen mode Exit fullscreen mode

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 whereas componentDidMount 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>

Enter fullscreen mode Exit fullscreen mode

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} />
...

Enter fullscreen mode Exit fullscreen mode

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 }) {

Enter fullscreen mode Exit fullscreen mode

Now, if we add a useEffect hook like this:

  function Counter({ count, isDark }) {
+ useEffect(() => {
+ console.log("isDark value changed")
+ }, [isDark])

Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

Top comments (0)