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

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

问题描述

我正在设计一个使用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)当服务器从客户端,它将为当前的所有项目发送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根据新商品信息和用户界面更新商店显示

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)重复

但是我不确定到底应该在哪里保持hub单例,因为这似乎与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集成在一起,就像在我的主索引页面中一样,我必须传递创建的商店到提供者组件,因此我不能将集线器创建置于此之下,因为您需要将信号中间件组件的集线器传递到商店创建中

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/signalr进行的操作 https://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.

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

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