Last updated: Apr 7, 2024
Reading timeยท3 min

To update state when props change in React:
useEffect hook.useEffect is rerun.import {useEffect, useState} from 'react'; function Child({parentCount}) { const [childCount, setChildCount] = useState(0); useEffect(() => { setChildCount(parentCount * 2); console.log('useEffect logic ran'); }, [parentCount]); // ๐๏ธ Add props as dependencies return ( <div> <button>Child count {childCount}</button> </div> ); } export default function Parent() { const [parentCount, setParentCount] = useState(0); return ( <div> <button onClick={() => setParentCount(current => current + 1)} > Parent count: {parentCount} </button> <hr /> <Child parentCount={parentCount} /> </div> ); }

We used the useEffect hook to update the state of a component when its props change.
useEffect(() => { setChildCount(parentCount * 2); console.log('useEffect logic ran'); }, [parentCount]); // ๐๏ธ Add props as dependencies
The logic in the useEffect hook is rerun every time one of its dependencies
changes.
Every time the parentCount prop changes, the useEffect hook is rerun and we
use the setChildCount function to update the state.
useEffect hook.Note that the function we passed to the useEffect hook is also invoked on the
initial render.
useEffect on the initial renderIf you don't want to run the logic in your useEffect hook on the initial
render, but only when the specific prop changes, use a ref to return early on
the initial render.
import {useEffect, useRef, useState} from 'react'; function Child({parentCount}) { const [childCount, setChildCount] = useState(0); const isFirstRender = useRef(true); useEffect(() => { if (isFirstRender.current) { isFirstRender.current = false; return; // ๐๏ธ Return early if first render } setChildCount(parentCount * 2); console.log('useEffect logic ran'); }, [parentCount]); return ( <div> <button>Child count {childCount}</button> </div> ); } export default function Parent() { const [parentCount, setParentCount] = useState(0); return ( <div> <button onClick={() => setParentCount(current => current + 1)}> Parent count: {parentCount} </button> <hr /> <Child parentCount={parentCount} /> </div> ); }

We used a ref to exit early when the
useEffect hook is run on mount.
Use this approach if you want to listen for props changes but need to skip the first render.
I've also written a detailed guide on how to call a child function from a parent component.
It should be noted that if you update the value of a prop and the prop is present in the hook's dependencies array, you would cause an infinite re-render loop.
Here is an example that demonstrates this issue.
import {useEffect, useState} from 'react'; function Child({parentCount, setParentCount}) { useEffect(() => { // ๐๏ธ This causes an infinite loop setParentCount(current => current + 1); console.log('useEffect logic ran'); }, [parentCount, setParentCount]); // ๐๏ธ parentCount is a dependency return ( <div> <button>Parent count {parentCount}</button> </div> ); } export default function Parent() { const [parentCount, setParentCount] = useState(0); return ( <div> <Child setParentCount={setParentCount} parentCount={parentCount} /> </div> ); }

The issue is that we added the parentCount prop to the hook's dependencies
array but we are also updating its value in the hook.
Every time useEffect is run, the value of parentCount is changed, which
re-runs the hook again because parentCount is in its dependencies array.
I've also written an article on how to update a component's state on click.