DEV Community

Lauren Slayman
Lauren Slayman

Posted on

useEffect(): Making Side Effects More Manageable in React Apps Since 2019

Imagine this: you're building a React app for the first time -- you're drafting up a wireframe and trying to envision how all of the pages and components will fit together and you realize some of them will need to pull a little more weight than others. While some only need to render their particular components, others may require a little more functionality, maybe they're fetching data, updating the DOM or managing a timer; basically, if the component is doing anything other than simply returning a bit of JSX, it's performing side effects. Luckily, React has special hook for these tasks: useEffect().

For demonstration purposes, let's build a component that counts clicks.

To start, you'll call useEffect() in almost the same manner as calling state at the top the of the component:

import React, { useState, useEffect } from 'react';

From there, we'll build out the rest of the component, directing it exactly what we want it to produce:

function ExampleComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // This function will be called after every render
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times.</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

In the example above, our component is displaying a count as well as a button. When clicked, the button's state is incremented via 'count' and the useEffect() hook is updating the document title with the current count each time it renders.

As you can see, when calling useEffect(), it takes a function as its primary argument (which is being called after each render), and updates the 'document.title' property accordingly.

Notice that there are no additional arguments to the useEffect() hook, so it will be called after every render. If we want it to be called only when the 'count' variable changes, we could simply pass it through as the second argument, like so:

useEffect(() => {
   document.title = `You clicked ${count} times!`;
}, [count]);
Enter fullscreen mode Exit fullscreen mode

This is known as a dependency, which prevents the code from running an endless loop of arguments. And while we have the option to pass the dependencies through arrays like we did above, we can also pass empty arrays through our functions as second arguments, as demonstrated below:

import React, { useState, useEffect } from 'react';

function ExampleComponent() {
  const [data, setData] = useState([]);

  useEffect(() => {
    // This function will be called once on component mount
    fetch('https://example.com/data')
      .then(response => response.json())
      .then(data => setData(data))
  }, []);

  return (
    <ul>
      {data.map(item => (
        <li key={item.id}>{item.title}</li>
      ))}
    </ul>
  );
Enter fullscreen mode Exit fullscreen mode

By utilizing the empty array as the second argument, we're telling our component that we only want the side effect to run the first time our component renders, once again preventing an endless loop.

Not sure when or how to pass dependencies through the second argument of useEffect? Here's a short guide!

  • useEffect(() => {}): No dependencies! This means the side effect will run every time the component renders.

  • useEffect(() => {}, []): Once again, there's that empty array! This tells our component that we only want the side effect to run the first time it renders.

  • useEffect(() => {}, [variable1, variable2]): This one may look new -- it's a dependencies array with elements and it communicates that the side effect should run whenever the variable(s) change.

Although this is just a brief overview, the useEffect() hook is an invaluable took when it comes to making components more dynamic and interactive, as it allows them to respond to changes in state, user interactions, or even external events. By using this hook to manage side effects, your components' functionality can be optimized to update in real time, interact with external data sources, manage animations and transitions and so much more! I hope you'll practice utilizing this method in your React apps to experience just how powerful individual components can become. Happy coding!

Top comments (0)