如何在 useEffect() 语句中使用 Socket.IO?

How to use Socket.IO in useEffect() statement?

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

我在事件 newOrder 上有一个侦听器,每次从后端发出 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

一般承诺是resolved/reject只有一次然后就没有了。但是 socket.io 可以发出不止一条消息。我建议您修改 WS 包装器方法以添加事件侦听器而不是 promise

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

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