用React套接字挂钩更新状态的正确方法

时间:2020-06-03 03:42:12

标签: reactjs react-hooks use-effect

我是一个反应初学者,我觉得这个问题过去曾被问过几次,但我看不出要使它正常工作是我所缺少的。

我正在写一个基于浏览器的简单游戏。我正在使用socket-io连接到服务器,并且正在使用自定义钩子来获取服务器发送的状态

  export const useSocketState = (serverUrl: string) => {
    const [isConnected, setConnected] = useState(false)
    const [socketId, setSocketId] = useState('')
    const [gameState, setGameState] = useState(DEFAULT_INITIAL_STATE)
    useEffect(() => {
      const client = socket.connect(serverUrl)
      client.on("connect", () => {
        console.log("connected with id " + client.id)
        setConnected(true)
        setSocketId(client.id)
      });
      client.on("disconnect", () => {
        setConnected(false)
      });
      client.on("gameStateUpdate", (data: ClientGameState) => {
        console.dir("Recieved new state from server" + data);
        console.dir("GameState is " + gameState);
        setGameState(prevState => {
          const newState = data
          console.log(" new state is " + newState)
          return newState
        })
      });
    }, gameState);

    return {gameState, isConnected, socketId}
  }

我在要引用此钩子返回的gameState的组件中使用此钩子。

我期望服务器发送新状态时,我的gameState实际上设置为新状态。当服务器返回新状态时,我确实看到了日志语句,其中打印了一个newState,但是我没有看到它反映在我正在使用的组件中。

Game component

  import React from "react";
  import {useSocketState} from "./useSocket";
  import {ClientGameState} from "../game/GameState";

  export function GameComponent(props: any) {
  const {gameState, isConnected, socketId} = useSocketState("http://127.0.0.1:8080");

    if (gameState.state === 'created') {
      return (

        <div>
          <p> Game id for this game: {props.location.state.gameId} and playerId:  {props.location.state.playerId} </p>
          <p>{JSON.stringify(gameState)}</p>
        </div>

      );
    } else {
      return (
        <div>
          <p> Game state is not created </p>
        </div>
      )
    }
  }

3 个答案:

答案 0 :(得分:0)

 export const useSocketState = (serverUrl: string) => {
    const [isConnected, setConnected] = useState(false)
    const [socketId, setSocketId] = useState('')
    const [gameState, setGameState] = useState(DEFAULT_INITIAL_STATE);

    function socketConnection(){
      const client = socket.connect(serverUrl)
      client.on("connect", () => {
        console.log("connected with id " + client.id)
        setConnected(true)
        setSocketId(client.id)
      });
      client.on("disconnect", () => {
        setConnected(false)
      });
      client.on("gameStateUpdate", (data: ClientGameState) => {
        console.dir("Recieved new state from server" + data);
        console.dir("GameState is " + gameState);
        setGameState(prevState => {
          const newState = data
          console.log(" new state is " + newState)
          return newState
        })
      });
    }
    useEffect(() => {
      socketConnection();
    }, []);

    return {gameState, isConnected, socketId}
  }

连接到套接字时,无需再使用useEffect()

答案 1 :(得分:0)

安装组件时需要建立套接字连接。因此,您需要useEffect的第二个参数:

useEffect(() => {
  // ... connection
}, []) // run on component mount

当某些变量更改时,您也可以使用useEffect

useEffect(() => { // additional useEffect hook
  // ... changes being detected
}, [gameState])

答案 2 :(得分:0)

仅将套接字返回的数据传递给setGameState挂钩。

client.on("gameStateUpdate", (data: ClientGameState) => {
    setGameState(data);
  });