I'm attempting to build a board game similar to Rubik's Race. The board gets randomly generated each time the game loads. This is what I have so far:
interface GameBoardProps {
initialConfiguration: GamePiece[];
}
function GameBoard({ initialConfiguration }: GameBoardProps) {
console.log("Drawing board");
const [gamePieces, setGamePieces] = useState(initialConfiguration);
for (let gamePiece of gamePieces) {
console.log(gamePiece.color);
}
const gamePieceSize = gamePieces[0].size;
const isEmptySpace = (index: number): boolean => {
return gamePieces[index].color === "black";
};
const isAtLeftEdge = (index: number): boolean => {
return index % 5 === 0;
};
const isAtRightEdge = (index: number): boolean => {
return index % 5 === 4;
};
const isAtTopEdge = (index: number): boolean => {
return index < 5;
};
const isAtBottomEdge = (index: number): boolean => {
return index >= 20;
};
const shiftLeft = (leftIndex: number, index: number) => {
setGamePieces((gamePieces) => {
const gamePiecesCopy = [...gamePieces];
var tempNullPiece = gamePiecesCopy[leftIndex];
for (; leftIndex < index; leftIndex++)
gamePiecesCopy[leftIndex] = gamePiecesCopy[leftIndex + 1];
gamePiecesCopy[leftIndex] = tempNullPiece;
return gamePiecesCopy;
});
};
const shiftRight = (rightIndex: number, index: number) => {
setGamePieces((gamePieces) => {
const gamePiecesCopy = [...gamePieces];
var tempNullPiece = gamePiecesCopy[rightIndex];
for (; rightIndex > index; rightIndex--)
gamePiecesCopy[rightIndex] = gamePiecesCopy[rightIndex - 1];
gamePiecesCopy[rightIndex] = tempNullPiece;
return gamePiecesCopy;
});
};
const shiftUp = (topIndex: number, index: number) => {
setGamePieces((gamePieces) => {
const gamePiecesCopy = [...gamePieces];
var tempNullPiece = gamePiecesCopy[topIndex];
for (; topIndex < index; topIndex += 5)
gamePiecesCopy[topIndex] = gamePiecesCopy[topIndex + 5];
gamePiecesCopy[topIndex] = tempNullPiece;
return gamePiecesCopy;
});
};
const shiftDown = (bottomIndex: number, index: number) => {
setGamePieces((gamePieces) => {
const gamePiecesCopy = [...gamePieces];
var tempNullPiece = gamePiecesCopy[bottomIndex];
for (; bottomIndex > index; bottomIndex -= 5)
gamePiecesCopy[bottomIndex] = gamePiecesCopy[bottomIndex - 5];
gamePiecesCopy[bottomIndex] = tempNullPiece;
return gamePiecesCopy;
});
};
const handleClick = (index: number) => {
let left = index,
right = index,
top = index,
bottom = index;
let shifted = false;
console.log("Clicked");
while (!(shifted || isAtLeftEdge(left))) {
console.log("Checking left side");
left -= 1;
if (isEmptySpace(left)) {
shiftLeft(left, index);
shifted = true;
}
}
while (!(shifted || isAtRightEdge(right))) {
console.log("Checking right side");
right += 1;
if (isEmptySpace(right)) {
shiftRight(right, index);
shifted = true;
}
}
while (!(shifted || isAtTopEdge(top))) {
console.log("Checking top side");
top -= 5;
if (isEmptySpace(top)) {
shiftUp(top, index);
shifted = true;
}
}
while (!(shifted || isAtBottomEdge(bottom))) {
console.log("Checking bottom side");
bottom += 5;
if (isEmptySpace(bottom)) {
shiftDown(bottom, index);
shifted = true;
}
}
};
return (
<div
className="game-board"
style={{
gridTemplate: `repeat(5, ${gamePieceSize}) / repeat(5, ${gamePieceSize})`,
}}
>
{gamePieces.map((piece, index) => (
<Square
key={piece.id}
size={piece.size}
color={piece.color}
onClick={() => handleClick(index)}
/>
))}
</div>
);
}
GameBoard is initialized from the App component like so:
const randomizePieces = (gamePieceSize: string) => {
console.log("randomizing board");
const gameBoard: GamePiece[] = [
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "blue" })),
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "white" })),
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "green" })),
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "orange" })),
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "red" })),
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "yellow" })),
{ id: 0, size: gamePieceSize, color: "black" },
];
for (let i = 0; i < 15; i++) {
const randA = Math.floor(Math.random() * gameBoard.length),
randB = Math.floor(Math.random() * gameBoard.length);
const temp = gameBoard[randA];
gameBoard[randA] = gameBoard[randB];
gameBoard[randB] = temp;
}
for (let i = 0; i < gameBoard.length; i++) gameBoard[i].id = i;
return gameBoard;
};
const gamePieces = randomizePieces("50px");
function App() {
return <GameBoard initialConfiguration={gamePieces} />;
}
The unexpected behavior I'm noticing is this: Initially after loading the game board, game pieces are able to shift around the first time a valid board piece is clicked, but they do not shift around on consecutive clicks. I notice on consecutive clicks that the logs are being printed, indicating that the appropriate functions are being called, but nothing is getting redrawn. This is only happening in StrictMode though; when I disable StrictMode the board behaves as expected (shifting valid pieces into the "empty" space). Anyone know what's happening and how I can change the code to work in development, using StrictMode?
I'm attempting to build a board game similar to Rubik's Race. The board gets randomly generated each time the game loads. This is what I have so far:
interface GameBoardProps {
initialConfiguration: GamePiece[];
}
function GameBoard({ initialConfiguration }: GameBoardProps) {
console.log("Drawing board");
const [gamePieces, setGamePieces] = useState(initialConfiguration);
for (let gamePiece of gamePieces) {
console.log(gamePiece.color);
}
const gamePieceSize = gamePieces[0].size;
const isEmptySpace = (index: number): boolean => {
return gamePieces[index].color === "black";
};
const isAtLeftEdge = (index: number): boolean => {
return index % 5 === 0;
};
const isAtRightEdge = (index: number): boolean => {
return index % 5 === 4;
};
const isAtTopEdge = (index: number): boolean => {
return index < 5;
};
const isAtBottomEdge = (index: number): boolean => {
return index >= 20;
};
const shiftLeft = (leftIndex: number, index: number) => {
setGamePieces((gamePieces) => {
const gamePiecesCopy = [...gamePieces];
var tempNullPiece = gamePiecesCopy[leftIndex];
for (; leftIndex < index; leftIndex++)
gamePiecesCopy[leftIndex] = gamePiecesCopy[leftIndex + 1];
gamePiecesCopy[leftIndex] = tempNullPiece;
return gamePiecesCopy;
});
};
const shiftRight = (rightIndex: number, index: number) => {
setGamePieces((gamePieces) => {
const gamePiecesCopy = [...gamePieces];
var tempNullPiece = gamePiecesCopy[rightIndex];
for (; rightIndex > index; rightIndex--)
gamePiecesCopy[rightIndex] = gamePiecesCopy[rightIndex - 1];
gamePiecesCopy[rightIndex] = tempNullPiece;
return gamePiecesCopy;
});
};
const shiftUp = (topIndex: number, index: number) => {
setGamePieces((gamePieces) => {
const gamePiecesCopy = [...gamePieces];
var tempNullPiece = gamePiecesCopy[topIndex];
for (; topIndex < index; topIndex += 5)
gamePiecesCopy[topIndex] = gamePiecesCopy[topIndex + 5];
gamePiecesCopy[topIndex] = tempNullPiece;
return gamePiecesCopy;
});
};
const shiftDown = (bottomIndex: number, index: number) => {
setGamePieces((gamePieces) => {
const gamePiecesCopy = [...gamePieces];
var tempNullPiece = gamePiecesCopy[bottomIndex];
for (; bottomIndex > index; bottomIndex -= 5)
gamePiecesCopy[bottomIndex] = gamePiecesCopy[bottomIndex - 5];
gamePiecesCopy[bottomIndex] = tempNullPiece;
return gamePiecesCopy;
});
};
const handleClick = (index: number) => {
let left = index,
right = index,
top = index,
bottom = index;
let shifted = false;
console.log("Clicked");
while (!(shifted || isAtLeftEdge(left))) {
console.log("Checking left side");
left -= 1;
if (isEmptySpace(left)) {
shiftLeft(left, index);
shifted = true;
}
}
while (!(shifted || isAtRightEdge(right))) {
console.log("Checking right side");
right += 1;
if (isEmptySpace(right)) {
shiftRight(right, index);
shifted = true;
}
}
while (!(shifted || isAtTopEdge(top))) {
console.log("Checking top side");
top -= 5;
if (isEmptySpace(top)) {
shiftUp(top, index);
shifted = true;
}
}
while (!(shifted || isAtBottomEdge(bottom))) {
console.log("Checking bottom side");
bottom += 5;
if (isEmptySpace(bottom)) {
shiftDown(bottom, index);
shifted = true;
}
}
};
return (
<div
className="game-board"
style={{
gridTemplate: `repeat(5, ${gamePieceSize}) / repeat(5, ${gamePieceSize})`,
}}
>
{gamePieces.map((piece, index) => (
<Square
key={piece.id}
size={piece.size}
color={piece.color}
onClick={() => handleClick(index)}
/>
))}
</div>
);
}
GameBoard is initialized from the App component like so:
const randomizePieces = (gamePieceSize: string) => {
console.log("randomizing board");
const gameBoard: GamePiece[] = [
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "blue" })),
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "white" })),
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "green" })),
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "orange" })),
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "red" })),
...Array(4)
.fill(null)
.map(() => ({ id: 0, size: gamePieceSize, color: "yellow" })),
{ id: 0, size: gamePieceSize, color: "black" },
];
for (let i = 0; i < 15; i++) {
const randA = Math.floor(Math.random() * gameBoard.length),
randB = Math.floor(Math.random() * gameBoard.length);
const temp = gameBoard[randA];
gameBoard[randA] = gameBoard[randB];
gameBoard[randB] = temp;
}
for (let i = 0; i < gameBoard.length; i++) gameBoard[i].id = i;
return gameBoard;
};
const gamePieces = randomizePieces("50px");
function App() {
return <GameBoard initialConfiguration={gamePieces} />;
}
The unexpected behavior I'm noticing is this: Initially after loading the game board, game pieces are able to shift around the first time a valid board piece is clicked, but they do not shift around on consecutive clicks. I notice on consecutive clicks that the logs are being printed, indicating that the appropriate functions are being called, but nothing is getting redrawn. This is only happening in StrictMode though; when I disable StrictMode the board behaves as expected (shifting valid pieces into the "empty" space). Anyone know what's happening and how I can change the code to work in development, using StrictMode?
Share Improve this question asked Mar 27 at 18:31 Oni BarolliOni Barolli 931 gold badge1 silver badge9 bronze badges 1- Step 1: ignore React, do all of it in plain JS and then only as almost an after thought, turn the resulting JS data structure into a bunch of JSX elements. Because this is one of those things where it's completely irrelevant what framework you're using, you first generate your data, then in as little code as possible you map that data to UI elements. Anything done "inside" a React component that isn't about recording state updates and turning finalized data into UI elements is code that doesn't belong there. – Mike 'Pomax' Kamermans Commented Mar 27 at 18:48
1 Answer
Reset to default 0StrictMode calls your state setters twice (but only keeps the result of the second call). Because of this your setters have to be idempotent, but yours have a tricky side-effect!
In your shift handlers, e.g., shiftUp
, your setter, setGamePieces(...)
, is capturing the arguments passed, topIndex
and index
, then inside the setter, you are modifying topIndex
in the for loop. So here's what happens:
- StrictMode calls setGamePieces() the first time with
topIndex
= 12 andindex
= 22 (for example) - In the setter, your for loop updates
topIndex
to 22 while it shifts the pieces correctly - Your setter returns the correct updated state
- StrictMode discards this result, and calls the setter a second time
- This time,
topIndex
is already 22, so it doesn't make any changes because it is already >=index
, and your setter returns the state effectively unchanged. - StrictMode accepts this result and re-renders
To fix it, use a new indexing variable instead of modifying the topIndex
directly, e.g.,
var i = topIndex;
var tempNullPiece = gamePiecesCopy[i];
for (; i < index; i += 5)
gamePiecesCopy[topIndex] = gamePiecesCopy[i + 5];
gamePiecesCopy[i] = tempNullPiece;
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744073278a4553932.html
评论列表(0条)