在 React/Redux 应用程序中将 SignalR 集线器放在哪里? [英] Where to put SignalR hub in React/Redux app?

查看:25
本文介绍了在 React/Redux 应用程序中将 SignalR 集线器放在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在设计一个使用 Redux 作为状态存储的 React 网站,主要是向用户显示当前的项目数量,使用实时更新使用 SignalR 更新项目数量.

I'm designing a React website using Redux as the state store, which is primarily to display the current population of items to the user, using live updates to update the item population using SignalR.

我想要这样做的方法是让 SignalR 发送项目更新消息以在您连接到服务器集线器时初始化起始人口,以及随着时间的推移通过相同的消息类型进行更新.我将有一个函数接收 SignalR 消息并将其转换为 Redux 操作并分派到 Redux 存储,然后该存储将使用该操作更新状态,然后更新 UI.

The way I wanted to do this was to have SignalR send item update messages both to initialise the starting population when you connect to the server hub, as well as updates via the same message type as time goes on. I would have a function that takes a SignalR message and converts it to a Redux action and dispatches to Redux store, which would then use the action to update the state and then the UI.

所以想法是

1) 连接到 SignalR 服务器集线器,设置客户端处理程序功能对于 ItemUpdate 消息

1) Connect to SignalR server hub, with client handler function set up for ItemUpdate messages

2) 当服务器从服务器接收到 Connect()客户端,它为所有当前项目发送 ItemUpdate 消息人口

2) When server receives Connect() from the client, it sends ItemUpdate messages for all current items in the population

3) 客户端从 SignalR 接收这些消息,转换为动作并分派到 Redux 存储区

3) The client receives these messages from SignalR, transforms to actions and dispatches to the Redux store

4) Redux根据新商品信息和 UI 更新商店显示它

4) Redux updates the store based on the new item information and the UI displays it

5) 服务器意识到一个项目已被添加或更新,并且向客户端发送一条新的 ItemUpdate 消息以进行更新

5) Server realises an item has been added or updated and sends a new ItemUpdate message for the update to the client

6) 重复

然而,我不确定我应该把集线器单例放在哪里,因为这似乎与 React/Redux 设计背道而驰.有人可以建议最好的方法吗?

However I am not sure of exactly where I should keep the hub singleton as this seems counter to React/Redux design. Can someone advise on the best way to do this?

我的主应用

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import './index.css';
import registerServiceWorker from './registerServiceWorker';
import 'rxjs';
import store from './store/index';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root') as HTMLElement
);

registerServiceWorker();

我的商店创建文件

import { createStore, applyMiddleware } from 'redux';
import rootReducer from '../reducers/index';
import signalRMiddleware from '../signalr/middleware';

const store = createStore(rootReducer, applyMiddleware(signalRMiddleware));
export default store;

我的中间件用于将 SignalR 消息出站到服务器(已注释掉,因为我无权访问我需要的集线器对象)

My middleware for outbound SignalR messages to the server (commented out as I do not have access to the hub object I need for this to work

export default function signalRMiddleware(store: any) {
    return (next: any) => (action: any) => {
        if (action.signalR) {
            switch (action.type) {
                default:
                    {
                        //const myCurrentState = store.getState().objectWithinState;
                        //_hub.server.methodOnTheServer2(action.type, myCurrentState);
                    }
            }
        }
        return next(action);
    }
}

现在对于传入的消息...这是我从在线示例中获得的 signalR 启动函数的外壳 - 尚未实现,因为我还没有集线器和连接,并且不确定应该去哪里

Now for the incoming messages... this is the shell of a signalR start function I got from an online example - not yet implemented as I do not have the hub and connection yet and not sure where this should go

export function signalRStart(store: any, callback: Function) {
    _hub = $.connection.myHubName;

    _hub.client.firstClientFunction = (p1: any) => {
        store.dispatch({ type: "SERVER_CALLED_ME", a: p1 });
    }

    _hub.client.secondClientFunction = (p1: string, p2: string) => {
            store.dispatch({ type: "SERVER_CALLED_ME_2", value: p1 + p2 });
        }
    }

    $.connection.hub.start(() => callback());
}

这是网站上给出的示例,我找到了将它们联系在一起的代码,但是我没有看到它如何像在我的主索引页面中那样与 React/Redux 集成,我必须通过创建的商店到 Provider 组件,因此我不能将集线器创建放在此下方,因为您需要传递到商店创建中的信号器中间件组件的集线器

And this is the example given on the website I found the code on to tie it all together, however I do not see how this can integrate with React/Redux as in my main Index page, I have to pass the created store to the Provider component and so I cannot put the hub creation below this, as you need the hub for the signalr middleware component which is passed into the store creation

let _hub;

let store = createStore(
  todoApp,
  // applyMiddleware() tells createStore() how to handle middleware
  applyMiddleware(signalRMiddleware)
)

// Make sure signalr is connected
signalRStart(store, () => {
    render((...),
    document.getElementById("app-container"));
});

有人可以建议将 SignalR 集成到我的 React/Redux 应用程序的最佳方式吗?

Can someone advise on the best way to integrate SignalR into my React/Redux app?

推荐答案

适用于将来可能会发现此主题的人.

这是我的自定义中间件,它只建立连接并注册处理程序.请注意,我只想接收数据,对发送数据不感兴趣.

This is my custom middleware that only establishes the connection, and registers the handlers. Please note that I only would like to receive data, and not interested in sending data.

import {
  JsonHubProtocol,
  HttpTransportType,
  HubConnectionBuilder,
  LogLevel
} from '@aspnet/signalr'; // version 1.0.4

// action for user authentication and receiving the access_token
import { USER_SIGNED_IN } from '../actions/auth';

const onNotifReceived = res => {
  console.log('****** NOTIFICATION ******', res);
};

const startSignalRConnection = connection => connection.start()
  .then(() => console.info('SignalR Connected'))
  .catch(err => console.error('SignalR Connection Error: ', err));

const signalRMiddleware = ({ getState }) => next => async (action) => {
  // register signalR after the user logged in
  if (action.type === USER_SIGNED_IN) {
    const urlRoot = (window.appConfig || {}).URL_ROOT;
    const connectionHub = `${urlRoot}/api/service/hub`;

    const protocol = new JsonHubProtocol();

    // let transport to fall back to to LongPolling if it needs to
    const transport = HttpTransportType.WebSockets | HttpTransportType.LongPolling;

    const options = {
      transport,
      logMessageContent: true,
      logger: LogLevel.Trace,
      accessTokenFactory: () => action.user.access_token
    };

    // create the connection instance
    const connection = new HubConnectionBuilder()
      .withUrl(connectionHub, options)
      .withHubProtocol(protocol)
      .build();

    // event handlers, you can use these to dispatch actions to update your Redux store
    connection.on('OperationProgress', onNotifReceived);
    connection.on('UploadProgress', onNotifReceived);
    connection.on('DownloadProgress', onNotifReceived);

    // re-establish the connection if connection dropped
    connection.onclose(() => setTimeout(startSignalRConnection(connection), 5000));

    startSignalRConnection(connection);
  }

  return next(action);
};

export default signalRMiddleware;

在我的 store.js 文件中

And inside my store.js file

import signalRMiddleware from '../middlewares/signalRMiddleware';

...

createStore(rootReducer, {}, composeEnhancers(applyMiddleware(signalRMiddleware)));

2020 年 6 月更新这就是我们现在如何使用新包@microsoft/signalrhttps://stackoverflow.com/a/62162742/10232269这不是使用中间件方法.我们使用的是 Redux,但您不必使用 Redux 来使用这种方法.

UPDATE June 2020 This is how we do it now with the new package @microsoft/signalr https://stackoverflow.com/a/62162742/10232269 This is not using the middleware method. We use Redux, but you don't have to use Redux to utilize this method.

这篇关于在 React/Redux 应用程序中将 SignalR 集线器放在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆