When to use functions in the useEffect dependency array

Last updated : Jul 30, 2023 12:00 AM

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.

function doesn't use any propsDescription
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.

function uses propsDescription
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.

receives function through propsDescription
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

Hi, I'm Lance Raney, a dedicated Fullstack Developer based in Oklahoma with over 15 years of exp

Read more...