The Great Blog

4 Ways to useEffect()

September 15, 2019

Yet another article about one of most used React hooks. Only I won’t go much into details how does it work, but write a few examples and patterns for a quick reminder of how and when to use it.

What It Is?

It’s a hook that lets do side effects inside function components. It takes a function as a first argument, and an array of dependencies as the second:

React.useEffect(fn, [deps])`

It is being called in the render, which looks like this:

  • Preparing UI with the current state
  • Rendering results, i.e. <div>Hello World!</div>
  • Committing results to the DOM
  • Browser paints the screen
  • React calls useEffect()

On the last stage of the render cycle, useEffect() is called with the state, handlers and effects of that call. So every render will have their specific properties, which will never change but React always will apply the last render result.

When and How to Use It

It slightly differs from the class component lifecycle methods. The main difference is that lifecycle methods always have the reference to the latest state, while useEffect() will cash the state, handlers and effects of each render, and it will be different from the next one. But the good thing is that you can manipulate when to call the function inside useEffect() by specifying a dependency list or none.

I think of 4 possible ways to call the method:

  • once, when component mounts
  • on every component render
  • on every component render with a condition
  • when component unmounts

When Component Mounts

Usually, you would like to use it for fetching data or adding event listeners. To run the function once, add an empty dependency list. If there are no dependencies in it, that means it will stay the same all the time, and will not call the function again.

function MyComponent() {
    // ...
	React.useEffect(() => {
		callMeOnlyOnce()
	}, [])
    // ...
}

On Every Component Render

To call the function on each component render, skip adding the dependency list. No list, nothing to compare against, that means run the effect every time.

function MyComponent() {
    // ...
	React.useEffect(() => {
		runThisFunctionOnEveryRender();
	})
    // ...
}

On Every Component Render with a Condition

To call a function conditionally, specify the list of dependencies. And the rule of thumb is to always add those dependencies that you are using inside the useEffect().

function MyComponent() {
    // ...
	React.useEffect(() => {
		runIfOneOfTheDepsWillChange(dep1, dep2);
	}, [dep1, dep2])
    // ...
}

When Component Unmounts

To clean up (remove event listeners or stop data fetching with a side effect) after the component unmounts, a return statement with a function should be added inside the useEffect() hook.

function MyComponent() {
    // ...
	React.useEffect(() => {
		document.addEventListener();
		
		return () => {
			document.removeEventListener();
		}
	}, [])
    // ...
}

Take Away

The take away from this article would be to always specify the dependencies, that you are using in the effect. It will prevent from running the effect unconditionally, which might cause infinity loops and performance issues.


Linas Spukas

Hi there! My name is Linas Spukas, I am a full stack web developer and this is my blog. About stuff and things... in development. Enjoy.