I want to change State with child elements in React. However, when I click once, it is not immediately updated. Click twice, it shows the correct answer.
How to update async?
export default function Example() {
const onClick = async () => {
console.log('a', test)
// should be 'b', but console log 'a'
}
const [test, setTest] = useState('a')
return (
<ClickExample setTest={setTest} onClick={onClick} />
)
}
export default function ClickExample() {
const next = useCallback(
(alphabet: string) => {
setTest(alphabet)
onClick()
},
[onClick, setTest],
)
return <SelectButton onClick={() => next('b')} />
}
CodePudding user response:
You can receive the value to be updated as an argument from the onClick
callback. It'll be something like this:
export default function Example() {
const [test, setTest] = useState('a')
const handleClick = (newValue) => {
setTest(newValue);
}
return (
<ClickExample onClick={handleClick} />
)
}
export default function ClickExample({ onClick }) {
return <SelectButton onClick={() => onClick('b')} />
}
NOTE: You should avoid using useCallback()
when it is not necessary. Read more over the web but this article from Kent C. Dodds is a good start. As a rule of thumb: Never use useCallback()
/useMemo()
unless you REALLY want to improve performance after needing that improvement.
CodePudding user response:
In the first render, the value of test
is equal to'a'
. So when the console.log
is executed, it has already captured 'a'
as the value of test
state. (See closures and stale closures).
One way to fix this would be to create a handleClick
function in the parent component which receives the new value of test
as its input and set the state and log the new value(which will be updated in the next render) using its argument.
// ClickExample
const handleClick = (alphabet) => {
setTest(alphabet);
console.log('a', alphabet);
};