I have two components in my code. In the App component, I initialize the chosenCount with zero and then I set a different value(eg: 56). When I click the set button, the Counter component is receiving the chosenCount as inititalCount. Inside the Counter component, a new state is initialized with the passed in prop initialCount as counter.But the counter value is not initializing with the passed in prop and its value is always 0. Its showing the same in the UI also.
Why is the state initializing with 0. Is this the default React behavior
These are the 2 components
const App = () => {
const [enteredNumber, setEnteredNumber] = useState(0);
const [chosenCount, setChosenCount] = useState(0);
const handleChange = (event) => {
setEnteredNumber(event.target.value);
}
const handleSetClick = () => {
setChosenCount(enteredNumber);
setEnteredNumber(0);
}
return (
<>
<main>
<section id="configure-counter">
<h2>Set Counter</h2>
<input type="number" onChange={handleChange} value={enteredNumber} />
<button onClick={handleSetClick}>Set</button>
</section>
<Counter setCount={setChosenCount} initialCount={chosenCount} />
</main>
</>
);
}
const Counter = ({initialCount}) => {
const [counter, setCounter] = useState(initialCount);
const handleDecrement = () => {
setCounter((prevCounter) => prevCounter - 1);
}
const handleIncrement = () => {
setCounter((prevCounter) => prevCounter + 1);
}
return (
<section className="counter">
<p>
<button onClick={handleDecrement}>
Decrement
</button>
<span className="counter-output">{counter}</span>
<button onClick={handleIncrement}>
Increment
</button>
</p>
</section>
);
}
I tried with setting the value as a new number, I was expecting it to reflect in the UI with the new number, but it was always showing 0
3
Answers
useState
value is get initialized only first time so as soon as the value is initialized it won’t initialized it again. You have to usesetCounter
to set new value.First time when the component is mounted then the initial value is
0
that you are passing it toCounter
, But when you change the value of the parent component then its value won’t get updated because it is already initialized.CODESANDBOX
You can use
useEffect
to update value as soon as the value changesIt is because the behavior of state initialization in React is asynchronous, when you first render the Counter component, the initialCount prop may not have been updated yet.
Even though chosenCount gets updated when you click the "Set" button in the App component, the Counter component’s state does not automatically update to reflect the new value of initialCount.
you have to use the useEffect in the Counter Component.
The value you pass to
useState()
is only used once when the component initially mounts to determine the initialconter
state value that you destructure from it (const [counter, setCounter] = ...
). To quote the docs, it:The only way to persistently modify your state is to use the
setCounter
state setter function it returns, changing the value passed touseState()
won’t do that.It is generally considered an anti-pattern to have a local version of the state which is passed as props, even with updating it with
useEffect()
(as this causes two renders of the child to occur, see the docs for more information). Instead, for this particular example, use the state from your parent component when you renderCounter
rather than recreating the sate. You can use the state setter function it gets passed from the parent to update your state as well. This is known as "lifting" your state up, which you’ve effectively already done: