DEV Community

Cover image for Things that no one ever told you about useEffect() in React
kapeel kokane
kapeel kokane

Posted on • Edited on

Things that no one ever told you about useEffect() in React

Hello there!

Welcome to another React demystified post.


Last week, we covered the useState() hook. We took it to the fundamental level and asked ourselves the question - "What exactly is state?" 🤔.


In this week's post, we will look at the useEffect() hook. It is one of the complicated things that you need to deal with, while working on functional React components. But once you get the hang of it, there's no looking back.

useEffect() is an escape hatch

Look at this seemingly harmless piece of code & tell me what you think the output is going to be:

export default function App() {
  console.log('first');

  useEffect(() => {
    console.log('second');
  });

  console.log('third');
  return (
    <main>
      <h1>Hello World</h1>
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

At first glance, it looks as though the output will be

  • first
  • second
  • third

But, but, but...

The actual output is

  • first
  • third
  • second

Let us understand why that is the case.

If you notice closely, useEffect is a function, that takes in another function as its first argument. It then calls executes that function at a future point in time. Turns out, that it always calls the function after the React component is rendered and the DOM is updated. Even in case of the first render. If you are not clear about how a React component gets translated into something on the DOM, check out this video:

The explanation

Now that we see useEffect() as a kind of escape hatch than anything else, the above behaviour makes more sense.

What happens is this:

  • console.log(first) is executed and we see first
  • useEffect is executed and we supply a function to it
  • console.log(third) is executed and we see third
  • React component is rendered, DOM update happens
  • useEffect executes the function we supplied & we see second

"So what is the point of the useEffect hook if it comes into the picture after the DOM is updated?", you might ask.

Well, it is to trigger side-effects (external).

According to the new React docs, it is quite clear what useEffect is meant for:

useEffect official

So what does this sentence - "synchronize with external system" actually mean?

Well, simply put, it means all the things that are "outside" of the React component. That includes things like:

  • API calls
  • DB interactions
  • Subscribing to external events

So whenever you see any useEffect, now you know that it is an escape hatch to take you out of the normal flow of code and do things that deal with external systems. Although the code is placed inside of the function component (to take advantage of the closure property & access local variables), do not think of it as something that executes in the same flow.

The usage

With that understanding in place, let us look at a few use cases of useEffect:

Side-effect on every render

This happens when we write code that looks something like the example above:

export default function App() {
  useEffect(() => {
    console.log('every render');
  });

  return (
    <main>
      <h1>Hello World</h1>
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

This kind of defeats the purpose of useEffect as it runs the side-effect every time the component is rendered.

side-effect once

If we pass an empty array as the second argument to useEffect, we are letting it know to run our function only once - right after the first render.

export default function App() {
  useEffect(() => {
    console.log('after first render');
  }, []);

  return (
    <main>
      <h1>Hello World</h1>
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

side-effect on dependency change

In this use-case, we are instructing useEffect to run the function every time a dependency is changed (by specifying the dependency in the array). This might be useful if the side-effect is dependent on the dependency.

export default function App() {
  useEffect(() => {
    console.log('count changed');
  }, [count]);

  return (
    <main>
      <h1>Hello World</h1>
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

summary

This sketchnote summarises it well:
useEffect summary

Hope that this article cleared up a lot of things like the need for something like useEffect() in the React paradigm. Also, hope that the 3 use cases are clear and that you will feel more confident in your "effects" henceforth.

Cheers! 🙌🏾

Top comments (1)

Collapse
 
kokaneka profile image
kapeel kokane

Thanks for the comment & adding the bit about strict mode. Will add a reference to it in the article :)