sajad torkamani

Note: You can use react-use ‘s useUpdateEffect (source) hook to do this instead of rolling out your own hook.

In a nutshell

If you want to run an effect only when the dependencies are updated but not on initial render, you’ll have to do something like this:

import React, { useEffect, useState } from 'react'
import useIsFirstRender from '../lib/hooks/useIsFirstRender'

const UseEffectOnlyWhenDependenciesUpdate: React.FC = () => {
  const isFirstRender = useIsFirstRender()
  const [name, setName] = useState('')

  useEffect(() => {
    if (!isFirstRender) {
      console.log(`Name has changed to "${name}"`)
    }
  }, [isFirstRender, name])

  function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
    setName(event.target.value)
  }

  return (
    <>
      <input
        type="text"
        placeholder="Name"
        value={name}
        onChange={handleChange}
        className="mb-2"
      />
    </>
  )
}

export default UseEffectOnlyWhenDependenciesUpdate

Notice the if (!isFirstRender) check inside the useEffect. If you don’t include this check, the effect will also run on initial render.

The useIsFirstRender hook can look something like this:

import { useRef } from 'react'

export default function useIsFirstRender() {
  // Assume first render by default
  const isFirstRender = useRef(true)

  if (isFirstRender.current) {
    // On first render, set isFirstRender flag to false
    // so that future renders know we've already rendered
    isFirstRender.current = false

    return true
  }

  return isFirstRender.current
}

Other notes

  • 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.

Sources