首页 > 解决方案 > 如何在 useEffect() 语句中使用 Socket.IO?

问题描述

我遇到了一件我不太明白的奇怪事情。

我有一个事件监听器,每次从后端发出newOrdera 时都应该收到该事件。newOrder这里的问题是,如果我这样使用它,useEffect(() => { ... }, [])它只会触发一次,这在某种程度上是有意义的,但是如果我像这样使用它,useEffect(() => { ... })它会因为新的渲染而触发太多次。

我的问题是,每次收到 newOrder 时,如何最好地在 useEffect 中使用它来监听,还是有更好的方法?

这是我的代码

  useEffect(() => {
    // WAIT FOR A NEW ORDER
    ws.on('newOrder').then(data => {
      dispatch(addOrder(data));
      dispatch(updateStatus('received'));
    });
    // CLIENT CANCELED
    ws.on('clientCanceledOrder').then(() => {
      dispatch(updateStatus('ready'));
      dispatch(clearPrice());
      alert('Your rider has canceled the order!');
    });

    return () => {
      ws.off('newOrder');
      ws.off('clientCanceledOrder');
    };
  }, []); 

这是我的 SocketClient.js

export default class socketAPI {
  socket;

  connect(user) {
    this.socket = io(BASE_URL, {
      query: `type=driver&id=${user}`,
      reconnection: true,
      transports: ['websocket', 'polling'],
      rememberUpgrade: true,
    });

    return new Promise((resolve, reject) => {
      this.socket.on('connect', () => {
        console.log(this.socket.io.engine.id);
        resolve(true);
      });

      this.socket.on('connect_error', error => reject(error));
    });
  }

  disconnect() {
    return new Promise(resolve => {
      this.socket.disconnect(reason => {
        this.socket = null;
        resolve(false);
      });
    });
  }

  emit(event, data) {
    return new Promise((resolve, reject) => {
      if (!this.socket) {
        return reject('No socket connection. Emit Event');
      }

      return this.socket.emit(event, data, response => {
        // Response is the optional callback that you can use with socket.io in every request.
        if (response.error) {
          return reject(response.error);
        }

        return resolve(response);
      });
    });
  }

  on(event) {
    // No promise is needed here.
    return new Promise((resolve, reject) => {
      if (!this.socket) {
        return reject('No socket connection. On event');
      }

      this.socket.on(event, data => {
        resolve(data);
      });
    });
  }

  off(event) {
    // No promise is needed here.
    return new Promise((resolve, reject) => {
      if (!this.socket) {
        return reject('No socket connection. On event');
      }

      this.socket.off(event, data => {
        resolve(data);
      });
    });
  }
}

然后我称之为这个const socketClient = new SocketClient();和这个

`useEffect(() => {
(async () => {
  const isConnected = await socketClient.connect(driver.id);

  dispatch(updateSocketStatus(isConnected));
})();
}, [driver]);` inside my context

标签: reactjssocket.io

解决方案


一般来说,承诺只解决/拒绝一次,然后不再。但是 socket.io 可以发出不止一条消息。我建议您重新编写 WS 包装器方法以添加事件侦听器而不是承诺

  on(event, listener) {
      if (!this.socket) {
           throw 'No socket connection. On event';
      }

      this.socket.on(event, listener);
  }

推荐阅读