When to use functions in the useEffect dependency array

Last updated : November 23, 2022

The useEfeect life cycle hook re-runs whenever its dependency array changes. There are two significant scenarios where a dependency array may require functions as dependencies.

  1. The function we use in useEffect uses props passed into the component.
  2. The component receives the function through props, and we use that function in useEffect

Take a look at the below code. My useEffect hook calls the printValue() function. The printValue() function doesn't use any props. Therefore I don't have to include it in the dependency array. React is aware of the function and its internals.

import { useEffect, useState } from "react";

const App = () => {
  const [text, setText] = useState<string>("")

  const printValue = (value: string) => {
      console.log(value)
  }

  useEffect(() => {
      printValue(text);
  },[text])

  return (
    <div>
        <textarea onChange={(e) => setText(e.target.value)}></textarea>
    </div>
  );
}
export default App;

The function uses props passed to the component.

Now I modify the same code to receive props, and I use that props in the function I call in the useEffect hook. In that case, I need to make two necessary changes.

The status of the printValue function now depends on the props. Therefore, the printValue function must be a part of the dependency array.

The printValue function is re-created every time the component re-renders. We only want to re-create it when the props.permissionGranted changes. Therefore, the printValue function needs to be wrapped in useCallback hook. That ensures that React returns the same function reference when the component re-renders. The reference only changes when props.permissionGranted is changed.

import { useCallback, useEffect, useState } from "react";
interface AppProps {
  permissionGranted?: boolean
}
const App = (props: AppProps) => {
  const [text, setText] = useState<string>("")

  const printValue = useCallback((value: string) => {
    if(!props.permissionGranted){
      console.log(value)
    }
  },[props.permissionGranted])

  useEffect(() => {
      printValue(text);
  },[printValue, text])

  return (
    <div>
        <textarea onChange={(e) => setText(e.target.value)}></textarea>
    </div>
  );
}
export default App;

The component receives the function through props.

Now my printValue function comes through props. So I need to include it in the dependency array to tell React to execute useEffect when the props.printValue function changes. Note that I destruct props and extract the printValue function outside the useEffect hook. That's to avoid including the entire props in the dependency array for performance reasons.

import { useEffect, useState } from "react";
interface AppProps {
  printValue?: (text: string) => void
}
const App = (props: AppProps) => {
  const [text, setText] = useState<string>("")
  const {printValue} = props

  useEffect(() => {
      printValue?.(text);
  },[printValue, text])

  return (
    <div>
        <textarea onChange={(e) => setText(e.target.value)}></textarea>
    </div>
  );
}
export default App;
Lance
By: Lance
Lance is a software engineer with over 15 years of experience in full-stack software development.
Read more...

Comments are disabled

No Comments