我正在实现一个井字游戏的客户端.
我有两份Typescript 文件:
- TicTacToe.tsx:Main Display,包含一个Switch语句,根据状态显示输入或游戏屏幕.
- TicTacTieAPI.tsx:游戏画面+后端;如果被调用,则建立一个WebSocket连接,并初始化客户端游戏状态.
在测试时,我得到以下错误:
TicTacToeAPI.tsx:5警告:Reaction检测到TicTacToe调用的Hook的顺序发生了更改.如果不进行修复,这将导致错误和错误.欲了解更多信息,请阅读《钩子规则:https://reactjs.org/link/rules-of-hooks》
Previous render | Next render | |
---|---|---|
1. | useState | useState |
2. | useState | useState |
3. | useState | useState |
4. | useState | useRef |
我不确定解决这个问题的标准方法是什么.
以下是这些文件:
TicTacToe.tsx
import React, { useState } from "react";
import TicTacToeAPI from "./TicTacToeAPI";
export default function TicTacToe() {
const [menuState, setMenuState] = useState("login");
const [nickname, setNickname] = useState("");
const [roomNumber, setRoomNumber] = useState(0);
return (
<div className="TicTacToe">
<h1>Tic Tac Toe</h1>
{(() => {
switch (menuState) {
case "login":
return input(setMenuState, setNickname, setRoomNumber);
case "game":
return game(setMenuState, roomNumber, nickname);
case "end":
return end();
default:
return null;
}
})()}
</div>
);
}
function game(
setMenuState: React.Dispatch<React.SetStateAction<string>>,
roomNumber: number,
nickname: string
) {
return (
<>
<div id="metaData">
<p>Room number: {roomNumber}</p>
<p>Nickname: {nickname}</p>
</div>
{TicTacToeAPI(nickname, roomNumber)}
<div id="abandonButton">
<button onClick={() => setMenuState("login")}>rage quit</button>
</div>
</>
);
}
function end() {
return <p>Game ended</p>;
}
function input(
setMenuState: React.Dispatch<React.SetStateAction<string>>,
setNickname: React.Dispatch<React.SetStateAction<string>>,
setRoomNumber: React.Dispatch<React.SetStateAction<number>>
) {
const [formData, setFormData] = useState({
nickname: "genericName",
roomNumber: 420,
});
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData({ ...formData, [e.target.id]: e.target.value });
};
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
// validate input
if (!formData.nickname || !formData.roomNumber) {
alert("Please enter a nickname and room number");
return;
}
// set parameters
setNickname(formData.nickname);
setRoomNumber(formData.roomNumber);
// change menu state
setMenuState("game");
};
return (
<div id="playerInfoInput">
<form className="playerInfo" onSubmit={handleSubmit}>
<h3>Nickname</h3>
<input
type="text"
id="nickname"
value={formData.nickname}
onChange={handleInputChange}
/>
<br />
<h3>Room number</h3>
<input
type="number"
id="roomNumber"
value={formData.roomNumber}
onChange={handleInputChange}
/>
<br />
<input type="submit" value="Submit" />
</form>
</div>
);
}
TicTacToeAPI.tsx
import React, { useEffect, useRef, useState } from "react";
export default function TicTacToeAPI(nickname: string, roomNumber: number) {
//websocket
const wsRef = useRef(new WebSocket("ws://localhost:8080/ticTacToe"));
//set other data
const [authToken, setAuthToken] = useState("");
(...)
//websocket
useEffect(() => {
//configure message handler
wsRef.current.onmessage = (message) => {
handleMessage(message, stateData);
};
// Cleanup WebSocket connection when the component unmounts
return () => {
wsRef.current.close();
};
}, []);
return (<p>board</p>)
}
根据我的研究,因为钩子是在它们自己的功能组件中,所以这种切换应该不是问题,但显然我误解了一些东西.