I started recreating the official React Tutorial using hooks.
I have encountered two issues I am struggling to solve.
Please refer to the CodePen for the full code, including line numbers.
Full Code
CodePen: React Tutorial with Hooks
Question 1
// Click handler
function handleClick(e) {
e.preventDefault();
// console.log('1) Inside Square click handler');
props.onUpdate();
// Logs un-updated value, probably because setState is async
console.log("props.value", props.value);
// STACKOVERFLOW QUESTION (Line 18)
// This still logs un-updated value (null). Why?
// PS: Line 23 logs the right value
window.setTimeout(() => {
console.log("props.value after timeout", props.value);
}, 1000);
}
// Logs correct value (Line 23)
console.log("props.value outside", props.value);
Line 18 logs a passed prop from within a handler, in a setTimeout. I am aware that state is set asynchronously, in line 9 (callback from parent). I understand that line 12 logs the value prior to the async state update, but I do not understand why the timeout still prints the wrong value.
Question 2
<div className = "status" >
{
(() => {
console.log("rendering, status:", status);
return status;
})()
}
</div>
Why is status in line 75 and 76 not reflecting the latest state change? I set it in line 62, then directly afterwards update state, which in return should cause a re-render with the right value. I am guessing the answer is that re-renders runs the entire function component again, resetting status (i.e. only state is saved). If that is right, how do we know exactly which components re-render on each state / prop / context update?
I am no expert so could be wrong a bit.
why the timeout still prints the wrong value.
Function Components (FC) are different from Class Components (CC) in a way that,
1. In FC, props contains the snapshot value after the render (using JavaScript closure)
1. In CC, props contains the updated value even after the render (because this.props can be changed as this is not immutable).
I've just read How Are Function Components Different from Classes?, yesterday and that's how the "wrong" values, null are showing up.
Initially, score array is [null x 9] thus props.value is set to null.
function Board() {
const [isXNext, setIsXNext] = React.useState(true);
// Initialize array with null values
const initialArray = Array(9).fill(null);
const [score, setScore] = React.useState(initialArray);
// onUpdate handler includes index, thus have to be arrow function
function renderSquare(i) {
return <Square value={score[i]} onUpdate={() => handleUpdate(i)} />;
}
...
}
And that null is closed over to window.setTimeout so props.value still has null after the time out.
function handleClick(e) {
...
window.setTimeout(() => {
console.log("props.value after timeout", props.value);
}, 1000);
}
Why is status in line 75 and 76 not reflecting the latest state change?
status is a local variable not a React state.
let status = `Next player: ${getPlayer()}`;
Mutating the status like the following won't re-render as React doesn't track the variable.
status = "Winner: " + winner;
Maybe you can declare the status as a state, like
const [status, setStatus] = React.useState(`Next player: ${getPlayer()}`);
And update the status using setStatus
if (winner) {
setStatus("Winner: " + winner);
console.log("game-won status:", status);
}
As mentioned, I've only read Dan's article yesterday so could not be 100% accurate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With