sajad torkamani

What is the purpose of useEffect?

useEffect lets you perform side-effects in functional components. It’s a replacement for the following lifecycle methods in a class component:

In class components, you place side-effects in the componentDidMount and componentDidUpdate methods. You clean up the side-effects in componentWillUnmount.

So, the following class component:

import React from 'react'

class Example extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 0
    }
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`
  }

  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`
  }

  componentWillUnmount() {
    // Do some clean up
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    )
  }
}

can be written as a functional component that uses useEffect:

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

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

  useEffect(() => {
    document.title = `You clicked ${count} times`

    return () => {
      // Do some clean up
    }
  })

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  )
}

When does useEffect run in the component lifecycle?

  • After the first render. When the component is initially mounted on the DOM and has finished rendering. You will have access to the initial state and props.
  • After every subsequent render. Every time the component has finished re-rendering, your effect will be executed. If you’ve listed any dependencies, it will only run if one of the dependencies has changed since the last render.

useEffect doesn’t block the browser painting process

Unlike componentDidMount or componentDidUpdate, effects scheduled with useEffect are deferred and executed after the browser has finished its layout and painting process. If you need to perform an effect before the next browser paint, you can use the useLayoutEffect instead.

Although deferred until after the browser has painted, useEffect is guaranteed to fire before the component is re-rendered. React will always finish the effect before starting a new re-render (need a working example of this).

How to use

Always run effect after each render (no dependencies)

useEffect(() => {
  console.log('Well, hello there')
})

Run effect only if dependencies are changed

If your effect depends on any props, state, or any other variables, you should pass these dependencies in the dependencies array. Conceptually, you can think of the dependencies array as arguments to your useEffect function – you should list everything that the effect depends on to do its work.

useEffect(() => {
  console.log('Well, hello there')
}, [dependency1, dependency2])

Run effect only on mount

useEffect(() => {
  console.log('Well, hello there')
}, []) // No dependencies - no need to ever re-run

Clean up effect when component unmounts

If you return a function from your useEffect hook, React will call this function before the component is removed from the DOM. If a component re-renders (as they typically do), the previous effect is cleaned up before executing the next effect.

useEffect(() => {
  const subscription = props.source.subscribe()
  return () => {
    // Clean up the subscription
    subscription.unsubscribe()
  }
})

Typical usages of useEffect

Examples of side-effects you’d place inside a useEffect hook are:

Other notes

The effect function will be different on every render

Every time a component is rendered (either initially or subsequently), the effect function will be a different function in the sense that it will be a new entity in the JavaScript engine’s memory heap.

Sources

Tagged: React