DEV Community

marisa saunders
marisa saunders

Posted on • Edited on

Understand the useEffect hook in react

The useEffect hook in react is one of the many hooks that you can use as a react developer.

A good place to start would be of an explanation of what exactly "hooks" are:

Hooks were introduced into React version 16.8 to solve the issue of developers often reusing the same code throughout different components as an alternate approach to classes. With hooks, instead of having complex components with stateful logic that cannot be reused, hooks introduced a way for developers to break up a component into smaller fragmented functions, based off of their functionality.

As a new developer I had learned to use functions and hooks before classes in React, but I advise you to try to code the same functionality using classes to truly understand the advantages.

With Hooks, you can extract stateful logic from a component so it can be tested independently and reused. Hooks allow you to reuse stateful logic without changing your component hierarchy. This makes it easy to share Hooks among many components or with the community - reactjs.org

The Effect Hook (useEffect)

Data fetching, subscriptions, and making manual changes to the DOM are all considered "side effects" meaning that they affect other components and cannot occur during rendering.

An operation, function or expression is said to have a side effect if it modifies some state variable value(s) outside its local environment — Wikipedia on Side Effects

The purpose of the useEffect hook was to introduce the ability to execute side effects from function components.

Calling useEffect tells react to execute your effect after React has updated the DOM (after every render). Because effects are declared inside of the component they have access to the both the components props and state.

In order to use the useEffect hook we first must import it from React.

import React, { useEffect } from "react";
Enter fullscreen mode Exit fullscreen mode

After doing so you can then call useEffect from within your component, here's a basic example of how to use the hook:

import React, { useEffect } from "react";

function ExampleUseEffect() {

  useEffect(() => {
    console.log("you just called useEffect WOO!");
  });

console.log("Component rendering");

return (
    <div>
      <button >Click to call useEFfect</button>
    </div>
  );
};

export default ExampleUseEffect;
Enter fullscreen mode Exit fullscreen mode

What order do you think the console messages appeared in? If you said "Component rendering" first and "you just called useEffect WOO!" second then you are correct! I am bringing this up to reinforce that useEffect is called AFTER rendering. By default, useEffect will run side effect functions every time the component re-renders:

render -> useEffect -> setState -> re-render -> useEffect

In the event that we don't want to make a network request every time our component is updated, and instead only the first time our component renders, we can tell react to only run our side effect in certain conditions.

Running the following code will result in an infinite loop of fetch requests which is most likely something we don't want to occur.

function MusicProjects() {
  const [musics, setMusics] = useState([]);
  const [count, setCount] = useState(0);

  useEffect(() => {
    fetch("http://localhost:3004/music/")
      .then((r) => r.json())
      .then((data) => {
        // setting state in the useEffect callback
        setMusics(data.message);
      });
  });

  return (
    <div>
      {musics.map((music) => (
        <img src={music} key={music} />
      ))}
    </div>
   <button onClick={() => setCount((count) => count + 1)}>
        I've been clicked {count} times
   </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

In order to mitigate when the side effect runs we can pass a second argument to useEffect known as a dependencies array. Passing a variable in the array will cause the side effect to run only when said variable changes, while passing an empty array as the second argument will cause the side effect to run only the first time that the component renders, solving the issue of the infinite loop in the previous example.

useEffect with a variable in the array (side effect will run only when the count variable changes):

useEffect(() => {
    fetch("http://localhost:3004/music/")
      .then((r) => r.json())
      .then((data) => {
        // setting state in the useEffect callback
        setMusics(data.message);
      });
  }, [count]);
Enter fullscreen mode Exit fullscreen mode

Empty dependencies array (side effect will run only the first time our component renders):

useEffect(() => {
    fetch("http://localhost:3004/music/")
      .then((r) => r.json())
      .then((data) => {
        // setting state in the useEffect callback
        setMusics(data.message);
      });
  }, []);
Enter fullscreen mode Exit fullscreen mode

You also have the ability to pass multiple variables into the dependencies array that will run whenever either of the variables change:

useEffect(() => {}, [variable1, variable2])
Enter fullscreen mode Exit fullscreen mode

Conclusion

• useEffect is one of the many hooks available in React

• useEffect is used to trigger side effects

• Dependencies arrays can but used to specify when the side effect will run

• An empty dependencies array will tell useEffect to run only the first time our component renders

Top comments (0)