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.
- The function we use in
useEffect
uses props passed into the component. - 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;