Redux+Websockets:为啥要使用中间件来管理这个?

Posted

技术标签:

【中文标题】Redux+Websockets:为啥要使用中间件来管理这个?【英文标题】:Redux+Websockets: Why manage this using middleware?Redux+Websockets:为什么要使用中间件来管理这个? 【发布时间】:2018-03-06 06:27:02 【问题描述】:

我一直在阅读有关将 WebSockets 集成到 React/Redux 应用程序的最佳方法的文章,我正在寻找答案,但其中的一些句子类似于“WebSocket 实现的最佳位置通常是中间件”。

我的问题是为什么这是首选?这样做与在外部 App 级 React 容器中设置 websocket/让侦听器调度操作(例如在 componentWillMount 中)有什么好处?

在应用程序的整个生命周期等方面,这似乎是等效的。我在这里缺少什么?

【问题讨论】:

【参考方案1】:

将这样的逻辑放在中间件而不是实际组件中有几个优点。 我认为主要原因是:

每个连接的组件都会实例化一个WebSocket 或者你会 需要一个连接的全局声明,它将是 独立于商店,换句话说,不属于redux 流。 Middle-Wares 可以访问商店并且是redux 的一部分 流。 您还可以访问整个商店,因此您可以通过 转发更多数据,然后最初发送。 您可以将组件与 Web 套接字逻辑分离,因此您可以 集中您的代码并重用您的组件。

总而言之,使用中间件的 web-sockets 并没有什么特别的原因,总的来说,使用中间件有很大的优势。

编辑 作为您评论的后续行动

您建议如何管理您可能需要 初始化 websocket 连接的特定组件,但想要 管理它是否已经连接,等等......它会像 很简单,就像在商店里有一个标志,表明它已连接或已连接 有更好的方法吗?

正如我所说,我不会在组件中初始化 web-socket 连接,而是在我的应用程序的入口点进行。比如index.js。 如果您关心的是确保在已有连接时不会尝试连接,那么在创建 store 并初始化时调用一个简单的 socketStart 方法您的所有应用程序数据,您可以将其传递给将进行渲染的回调,并通过dispatch 更新store。 一个简单的例子(记住这是一个伪代码):

我们的 Socket-start 方法:

export function socketStart(store, callback) 
  // this is only a pseudo code!

  // register to server -> client events
  _socketClient.someFunction = (data) => 
    store.dispatch( type: "Server_Invoked_Some_Function", data );
  

  _socketClient.someFunction2 = (data) => 
    store.dispatch( type: "Server_Invoked_Some_Function2", data );
  

  // connect to the server via the web-socket client API
  _socketClient.connect(() => callback());

我们可以在index.js 文件中使用它:

let store = createStore(
  // your reducers here...
  // ...
  applyMiddleware(socketMiddleware) // our web socket middleware
)

// the callback will invoked only if the connection was successful
// the React-Dom's render function is our callback in this case
socketStart(store, () =>  render(<App />, document.getElementById("root")); );

【讨论】:

这一切都说得通,谢谢!这里最大的原因似乎是,作为中间件,它将可以访问整个商店,而使用***组件进行连接是不可用的(或者会很奇怪/架构上很奇怪)。您如何建议管理您可能希望特定组件初始化 websocket 连接,但想要管理它是否已经连接等的情况......它是否就像在商店中显示它已连接的标志一样简单还是有更好的方法? 首先,我不会在组件中初始化 websocket 连接,而是在我的应用程序的入口点进行初始化(例如 index.js)。如果您关心的是确保在已经建立连接时不会尝试连接,那么在创建store 时调用一个简单的连接方法,您可以在其回调中呈现应用程序。我会用一个简单的例子来更新答案【参考方案2】:

使用中间件,您可以轻松地在 Redux 和 Web Socket 之间展开/中继消息。此外,您可以在没有 React 的情况下使用 Redux 中间件,这意味着您可以在服务器端代码上使用 Redux 编写 API(可能使用 Redux saga)。

我同意 React 组件的生命周期管理比 Redux 中间件更容易。但是如果要重新连接(destroy/recreate),则需要使用key props 让reconciler 将其视为一个新对象,这有点奇怪。

您可以查看redux-websocket-bridge,它将 Web Socket 消息展开为 Redux 操作,并将 Redux 操作中继到 Web Socket。

在您的 Web Socket 服务器上,您发送一个操作:

ws.on('connection', conn => 
  conn.send(JSON.stringify( 
    type: 'GREETING', 
    payload:  now: Date.now()  
  ));
);

您将在 Redux 减速器上获得 GREETING 操作。反之亦然,当你想将一个动作中继到 Web Socket 时,你用meta.sendtrue 标记你的动作:

this.props.dispatch( 
  type: 'SIGN_IN',
  meta:  send: true ,
  payload:  authToken: '...' 
);

【讨论】:

以上是关于Redux+Websockets:为啥要使用中间件来管理这个?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们需要中间件用于 Redux 中的异步流?

为啥我们需要中间件用于 Redux 中的异步流?

WebSocket 服务器中的 Redux

使用 Websockets 的 Redux-thunk

什么是Redux以及Redux的使用

redux学习日志:关于异步action