#reactjs #socket.io #react-hooks
Вопрос:
Ниже приведен код, с которым я изначально работал. Насколько я могу судить, этот код работает, если компонент повторно отображает и повторно подключает сокет, но не при начальной загрузке. Я дошел до определения того , что состояние обновляется номинально, когда я использую локальные значения из вызова дочернего компонента handleUpdateCell
, но, похоже, обновить значение из него невозможно socket.on()
.
interface MyComponentProps {
gameID: number;
}
export const MyComponent: React.FC<MyComponentProps> = (props) => {
const params = useParams<GameRouteParams>();
const gameID = parseInt(params.gameID!);
const [gameName, setGameName] = useState<string>();
const [positions, setPositions] = useState<ICell[]>();
const [lastUpdate, setLastUpdate] = useState<ICell>();
const [pawns, setPawns] = useState<Record<string, IPawn>>();
const [isLoading, setIsLoading] = useState(false);
const socket = useMemo(() => {
const ENDPOINT = `http://localhost`;
const APIPATH = `/api/source`;
return socketIOClient(ENDPOINT, {
path: APIPATH,
transports: ["websocket"], //TODO: I don't like this option atm, it means I'm misunderstanding something about CORS to get this far, but I just want to move forward
query: {
gameID: gameID.toString(),
},
});
}, [gameID]);
const handleUpdateCell: HandleUpdateCell = (id, x, y, clientDrop) => {
console.log({ positions: positions }); //THIS IS ALWAYS undefined (initial state)FROM SOCKET.ON('map-update')
if (positions) {
const positionUpdate = [...positions];
const positionIndex = positionUpdate.findIndex(
(cell) => cell.id === id
);
if (positionIndex > -1) {
const theCell = positionUpdate[positionIndex];
theCell.x = x;
theCell.y = y;
positionUpdate[positionIndex] = theCell;
setLastUpdate(theCell);
setPositions(positionUpdate);
if (clientDrop amp;amp; socket) {
socket.emit(`token-update:${gameID}`, theCell);
}
}
}
};
const handleMapUpdate = (cellUpdate: { positions: ICell[] }) => {
if (cellUpdate amp;amp; cellUpdate.positions) {
for (let i = 0; i < cellUpdate.positions.length; i ) {
const cell = cellUpdate.positions[i];
handleUpdateCell(cell.id, cell.x, cell.y, false);
}
}
};
useEffect(() => {
//connect via websockets to api
socket.on("connect", () => {
console.log("Connect");
socket.onAny((eventName, args) => {
console.log({ eventName, args });
});
socket.on(`game-init:${gameID}`, (gameInfo: IGameState) => {
console.log("Game Init");
console.log(gameInfo);
setGameName(gameInfo.name);
setPositions(gameInfo.positions);
setPawns(gameInfo.pawns);
setIsLoading(false);
});
socket.on(`map-update:${gameID}`, handleMapUpdate);
});
}, [gameID, socket, handleMapUpdate]);
useEffect(() => {
console.log({ Title: "Position useEffect", positions: positions });
}, [positions]);
Похоже, что старое состояние захвачено, поэтому я попытался добавить useCallback
:
const handleUpdateCell: HandleUpdateCell = useCallback((id, x, y, clientDrop) => {
console.log({ positions: positions });
if (positions) {
const positionUpdate = [...positions];
const positionIndex = positionUpdate.findIndex(
(cell) => cell.id === id
);
if (positionIndex > -1) {
const theCell = positionUpdate[positionIndex];
theCell.x = x;
theCell.y = y;
positionUpdate[positionIndex] = theCell;
setLastUpdate(theCell);
setPositions(positionUpdate);
if (clientDrop amp;amp; socket) {
socket.emit(`token-update:${gameID}`, theCell);
}
}
}
}, [positions, gameID]);
const handleMapUpdate = useCallback((cellUpdate: { positions: ICell[] }) => {
if (cellUpdate amp;amp; cellUpdate.positions) {
for (let i = 0; i < cellUpdate.positions.length; i ) {
const cell = cellUpdate.positions[i];
handleUpdateCell(cell.id, cell.x, cell.y, false);
}
}
}, [
handleUpdateCell
]);
К сожалению, это, похоже, не помогает. Я тоже useRef
примерял positions
, но это тоже был провал. Я предполагаю, что совершаю очень простую ошибку, но я нахожусь на 3-м часе отладки только этой проблемы.