Learning react here and doing the tic-tac-toe intro here: https://react.dev/learn/tutorial-tic-tac-toe
.
I’m trying to understand why my code isn’t working. I’m on the https://react.dev/learn/tutorial-tic-tac-toe#completing-the-game
portion, where you add components like:
<Square value={squares[8]} onSquareClick={() => handleClick(8)} />
I’m trying to take a slightly different approach and create the squares programmatically, like so:
export default function Board() {
const [squares, setSquares] = useState(Array(9).fill(null));
function handleClick(i) {
const nextSquares = squares.slice();
nextSquares[i] = "X";
setSquares(nextSquares);
}
var boardRows = [];
var counter = 0;
for (var i = 0; i < 3; i++) {
var boardSquares = [];
for (var j = 0; j < 3; j++) {
boardSquares.push(<Square value={squares[counter]} onSquareClick={() => handleClick(i)} />);
counter ++;
}
boardRows.push(<div className="board-row"> {boardSquares} </div>);
}
return boardRows;
}
The problem is, the handleClick(i)
is using 9, since that’s the final value of my counter. Is there a way to have the function "save" the value that will be passed in on the click? Or am I going about this wrong?
2
Answers
The issue you’re facing is due to the fact that the
handleClick
function you’re passing to theonSquareClick
prop inside the loop is always referencing the final value ofi
(which is 2 in this case). This happens because JavaScript closures capture the current value of variables.To fix this issue, you can modify your code by creating a new function within the loop that captures the value of
i
for each iteration. This way, the correct value ofi
will be used when calling thehandleClick
function. Here’s how you can do it:By creating a
const index = counter;
within the inner loop and usingindex
inside theonSquareClick
function, you ensure that the correct value ofindex
is captured and used for each square’s click event. This should solve the issue you were facing with the incorrect value ofi
in thehandleClick
function.There are many problems
i
you are passing in is only0
~2
due to its using the counter from the outer loop. Although it’s not what you are asking, the next one will answer your answervar
are available throughout the function (in this caseBoard
), soi
will always be the last value at the end of the loop. You could fix that by declaring withlet
but that doesn’t completely solve your problem, which leads to the next problem…Board
, but is not accurate. The easiest way to properly pass the value would be to define a value right before you pass it. In 95% of the cases,const
is your best bet. Below is the proper fix —The code here not only answers your question, and also fixes the bug where the square you are clicking isn’t aligned with what it is intended.
const
value is block scope, and isn’t mutatable, making it extra safe as a disposable value.Hope this helps.