【问题标题】:Why is socket.io-client's socket.on( ) getting fired up multiple times?为什么 socket.io-client 的 socket.on() 会被多次触发?
【发布时间】:2021-02-01 00:43:17
【问题描述】:

因此,由于某些原因,socket.once() 被多次启动,即使它们在 useEffect(); 我 100% 确定我不会在服务器 sde 上多次发出它们。 其中一些事件会被多次触发,有时甚至会导致内存泄漏。 这是我的 useEffect() 函数内部的代码;

useEffect(() => {
    socket.once('room-joined', (msg) => {
      setState({ ...state, roomID: msg.msg, roomJoined: true, room: msg.room, leader: false });
      console.log(msg.users);
      console.log(msg.msg);
    });

    socket.once('start-flip', (msg) => {
      gotFinalResults = false;
      gotResults = false;
      normalized = false;
      setState({ ...state, game: '/flip' })
    });
    socket.once('ask-choice-dice', () => {
      gotFinalResults = false;
      gotResults = false;
      normalized = false;

      setState({ ...state, game: '/dice' });

    });
    socket.once('round-result', (msg) => {
      rockChoice = 'rock';
      setState({ ...state, rockRoundResult: msg, rockChoice: 'rock' });
    });

    socket.once('race-finished', (msg) => {
      console.log(msg);
      setState({ ...state, raceFinished: true, raceList: msg });
    });

    socket.once('message', (msg) => {
      console.log(msg);
      messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
      setState({ ...state, chat: [...state.chat, { author: msg.username, msg: msg.msg }] });
    });
    socket.once('player-disconnected', (msg) => {
      setState({ ...state, room: msg.room, chat: [...state.chat, { author: null, msg: msg.msg }] });
    });
    socket.once('room-created', (msg) => {
      console.log(msg.msg);
      setState({ ...state, roomID: msg.msg, roomJoined: true, room: msg.room, leader: true });
    });
    socket.once('new-connection', (msg) => {

      setState({ ...state, room: msg.room, chat: [...state.chat, { author: null, msg: msg.msg }] });


    });

    socket.once('exit-lobby', (msg) => {
      setState({ roomID: '', roomJoined: false, joinRoomID: '', chat: [], chatBox: [], room: {}, game: '', leaderQuit: true, leader: false });
    });
    socket.once('start-race', () => {
      gotFinalResults = false;
      gotResults = false;
      normalized = false;
      setState({ ...state, game: '/race' });
    });
    socket.once('initialize-race', (msg) => {
      gotFinalResults = false;
      gotResults = false;
      normalized = false;
      setState({ ...state, game: '/race', raceText: msg.text, raceTimer: true, startTime: performance.now(), raceInitiated: true });

    });
    socket.once('normalize', () => {
      gotResults = false;
      gotFinalResults = false;
      setState({ ...state, game: '/', choice: Math.floor(Math.random() * 5) + 1, voluntarily: false, timer: { enabled: false }, leaderQuit: false, submitted: false, victory: false, defeat: false, winners: [], loosers: [], rockChoice: 'rock', rockRoundResult: false, rockGameResult: false, raceChoice: '', startTime: null, raceSpeed: 0, raceTimer: false, raceFinished: null, raceList: [], raceInitiated: false, flipChoice: 'heads' });
    });

    socket.once('defeat', () => {
      gotFinalResults = true;
      console.log('oh no!')
      setState({ ...state, defeat: true });
    });
    socket.once('results', (msg) => {
      setState({ ...state, winners: msg.winners, loosers: msg.loosers });

    })
    socket.once('victory', () => {
      gotFinalResults = true;
      setState({ ...state, victory: true });
      console.log('oh yes!')
    });
  });

【问题讨论】:

    标签: javascript reactjs socket.io


    【解决方案1】:

    删除除一个 .once 调用之外的所有调用应该会使问题非常明显:

    useEffect(() => {
        socket.once('room-joined', (msg) => {
            setState({ ...state, roomID: msg.msg, roomJoined: true, room: msg.room, leader: false });
            console.log(msg.users);
            console.log(msg.msg);
        });
        // lots of other code
    });
    

    由于没有依赖数组,因此每次组件重新渲染时都会重新运行此效果回调。第一次渲染时,将有一个监听器附加到给定事件。第二次渲染时,将有两个侦听器附加到给定事件。等等。

    使用一个空的依赖数组来确保.once 对每种类型只调用一次。

    您还需要使用状态设置器的回调形式才能正确更新它。

    useEffect(() => {
        socket.once('room-joined', (msg) => {
            setState(state => ({ ...state, roomID: msg.msg, roomJoined: true, room: msg.room, leader: false }));
            console.log(msg.users);
            console.log(msg.msg);
        });
        // lots of other code
    }, []);
    

    【讨论】:

    • 我试着按照你说的做,但显然,我无法访问 useEffect() 中 state 的当前值。你能告诉我是否有办法访问它吗?
    • 状态设置器使用回调形式。
    • 我知道这让我听起来有点像个傻瓜,但你能强调一下吗?回调表单是什么意思?你是说 useCallback 钩子吗?
    • 看答案。状态设置器 - setState - 使用回调而不是仅仅传递一个值。 setState(state => ({ ...state, 等。在构建新状态时,只要您需要最新的值,就可以使用它。
    • 非常感谢,朋友。我明白了。
    猜你喜欢
    • 2018-09-22
    • 1970-01-01
    • 2018-08-31
    • 1970-01-01
    • 1970-01-01
    • 2022-08-17
    • 2019-11-10
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多