如何在 React 中处理多个 websocket 订阅?

How to handle multiple websocket subscriptions in React?

我使用 websocket API 订阅了几个符号,例如 BTC-USD 和 EUR-USD。 响应以混合在消息流中的持续对象流(例如 {symbol: 'EUR-USD', price: '1.1'})的形式出现:一些带有 EUR-USD 的价格,一些带有BTC-USD 的价格。

我想在 table 中显示值。我该怎么做?

我想到了下面的东西(它不起作用):

this.socket.addEventListener('message', (e) => {
  e.data.symbol === 'EUR-USD' && this.setState({ pairEURUSD: JSON.parse(e.data) });
  e.data.symbol === 'BTC-USD' && this.setState({ pairBTCUSD: JSON.parse(e.data) });
});

然后在渲染方法中显示适当的状态对。

我还在渲染方法中想到了以下内容(它有点管用):

<p>{this.state.pair === 'BTC-USD' && this.state.pair.price}</p>
<p>{this.state.pair === 'EUR-USD' && this.state.pair.price}</p>

如果最新的输出消息是针对 BTC-USD 对,则这不会为 EUR-USD 呈现任何内容。我显然想渲染一些东西,最新的值,而一对没有更新的值。

关于如何在函数或 class 组件中或(可能更好)使用 redux-saga 实现的任何建议?

代码不多,但我认为您的想法是正确的。您可能只是对 reading/writing 状态有误。

如果你想使用 sagas,你首先需要 eventChannel 实用程序来包装监听器。

import {eventChannel} from 'redux-saga'

const socketChannel = eventChannel((emit) => {
  socket.addEventListener('message', emit)
  return () => socket.removeEventListener('message', emit)
})

然后您可以像对 redux 操作一样在该频道上使用 take 效果:

yield takeEvery(socketChannel, function* (message) {
  const {symbol, price} = JSON.parse(message.data)
  yield put(storeNewValue(symbol, price))
})

之后就是 react/reducer 数据的正常 react/reducer 逻辑,例如

// reducer
...
case STORE_NEW_VALUE:
  return {
    ...state,
    [action.symbol]: action.price,
  }
...
// react
const ItemTable = () => {
  const data = useSelector(state => state.path.to.data)
  const rows = Object.entries(data).map(([symbol, price]) => (
    <div>{symbol + ' ' + price}</div>
  ))
  return <div>{rows}</div>
}

在此处查看工作演示: https://codesandbox.io/s/dt8us?file=/src/index.js