The useEffect Hook

The useEffect Hook

Article 2 in my React Hooks mini-series

In my previous article, basic understanding of the useState Hook, I explained all there is to know about the useState hook in React with practical example. This is the second piece in my mini-series on React Hooks.

What is UseEffect Hook?

useEffect Hook is used to perform "side effects" in React. It runs a function on every render of the component. Some of these side effects are:

  • Fetching data
  • Manually updating/changing the DOM
  • Timer.

Why is useEffect Hook used?

  • It's executed after every render
  • It offers an optional clean-up function to unsubscribe any subscriptions.
  • It can skip an effect if certain values haven't changed between re-renders

Create your React app if you haven't and go to your App.js to practise using useEffect hook. Remember to import your useEffect hook at the top of your component

The useEffect hook accepts 2 arguments, the 2nd one being optional.

Without Dependency Array

The useEffect hook can run without the 2nd argument, that's the dependency array, to run a function every time there's a re-render

Simple demonstration of the useEffect Hook without the 2nd argument

import { useEffect } from 'react';

useEffect(() => {
    console.log("Testing useEffect Hook");
});

This runs every time you refresh your browser.

Demonstrating the useEffect Hook without the 2nd argument in a timer function

Using a function called "setTimeout" to count every one second after the initial render of useEffect hook.

import { useState, useEffect } from "react"; 
function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setTimeout(() => {
      setCount((count) => count + 1);
    }, 1000);
  });

return (
      <div className="App">
        <h1>UseEffect Hook Explained</h1>
        <h4>No dependency array passed. It runs on every render.</h4>
        <p>Number of counts: {count}</p>
      </div>
  );
}

export default App;

Now after the first render, the count renders every 1 second continuously until the page is refreshed, then it starts again from number zero(the set useState variable).

With a Dependency Array

This is used when we want to run a function only after a certain render. The dependency array is an array that you pass into the useEffect hook as the 2nd argument. It can be an empty array or an actual dependency array.

Demonstrating the dependency array by passing an empty array

Passing an empty array as the 2nd argument will make sure that the hook only runs the function after the initial render:

useEffect(() => {
  console.log("Testing out the useEffect empty dependency array")
}, []);

Demonstrating the useEffect Hook with an empty dependency array in a timer function

import { useState, useEffect } from "react"; 
function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    setTimeout(() => {
      setCount((count) => count + 1);
    }, 1000);
  }, []);

return (
      <div className="App">
        <h1>UseEffect Hook Explained</h1>
        <h4>Empty dependency array passed. It runs only after the first render.</h4>
        <p>Number of counts: {count}</p>
      </div>
  );
}

export default App;

Demonstration of the useEffect Hook with an empty dependency array in a timer function

Passing an Actual Dependency Array as a 2nd Argument

Here, we create a state value that changes when a button is clicked and we want the useEffect function to only run after the state changes.

import { useState, useEffect } from 'react';

function App() {
  const [word, setWord] = useState("Don't give up")

  useEffect(() => {
    console.log('useEffect ran');
    console.log(word);
  }, [word])

  return (
      <div className="App">
        <h1>UseEffect Hook Explained</h1>
        <h4>Passing an actual dependency in the array. The useEffect function runs when the state changes.</h4>
        <p>{word}</p>
        <button onClick={() => setWord("Learning React")}>Change Text</button>
      </div>
  );
}

export default App;

The "word" value in the useEffect array is telling the useEffect hook to only run when the state "word" is being changed. The useEffect function runs first on it being rendered and these 2 texts: "useEffect ran" and "Don't give up" will be printed out on the console. After clicking the Change Text button, the text then changes on the browser and the useEffect function runs once again while printing out those texts on the console again.

useEffect Cleanup

This is a function that allows us to clean up our code before our component unmounts. It's used to cleanup a useEffect function after a render.

useEffect cleanup can be used when setting up an event listener in the function. To make sure the cleanup code removes it so that you don't constantly have to re-add your event listener.

It is also important to clean up so that you don’t introduce a memory leak. Like when you subscribe to an API inside the useEffect. The return cleans it up after it has been rendered and unsubscribe you from that API.

import { useState, useEffect } from 'react';

function App() {
  const [word, setWord] = useState("Courses")
  useEffect(() => {
    console.log("Course changed")

    return () => {
      console.log("Course changed: Cleanup function called")
    };
  }, [word])

  return (
      <div className="App">
        <h1 className="topic">UseEffect Hook Explained</h1>
        <h4>useEffect Cleanup demo. The return function cleans up whatever render has been done beforehand</h4>
        <p>{word}</p>
        <button onClick={() => setWord("Learning React")}>React</button>
        <button onClick={() => setWord("Learning useEffect")}>useEffect</button>
      </div>
  );
}

export default App;

The return code in the useEffect function is considered a cleanup. Every time the useEffect runs, whatever is in the return gets to run first to clean up whatever was done previously.

You can view the useEffect Hook React documentation here.