javascript - 在 React/Redux 应用程序中将 SignalR hub 放在哪里?

标签 javascript reactjs redux signalr

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

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

所以思路是

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

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

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

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

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

6) Repeat

但是我不确定我应该将 hub 单例保存在哪里,因为这似乎与 React/Redux 设计背道而驰。有人可以建议最好的方法吗?

我的主要应用

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 消息的中间件(已注释掉,因为我无权访问此工作所需的集线器对象

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 启动函数的外壳 - 尚未实现,因为我还没有集线器和连接并且不确定它应该去哪里

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());
}

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

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 应用程序中的最佳方法吗?

最佳答案

供将来可能找到此主题的人使用。

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

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 文件中

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

...

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

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

关于javascript - 在 React/Redux 应用程序中将 SignalR hub 放在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50625267/

相关文章:

javascript - 运行文件 ://from http://localhost/

node.js - 即使在建立 Websocket 之后,Socket IO 仍保持(重新?)连接

javascript - 使用 CSS/Javascript 将文本更改为文本字段中的点

javascript - addClass 然后removeClass 同一个类

javascript - 如何在网络中只运行一个定时器

javascript - React/Redux,使用 Redux Thunk 实现多个操作

javascript - 如何在 React-Redux 上使两个组件相互连接

reactjs - React native 重新渲染导致 View 滚动到顶部 - 我的键在渲染之间会改变吗?

reactjs - React-createRef() Api-this.child.current 为 null

javascript - React/Redux : Component not redrawing despite correct dispatching and state change.(不涉及突变)