我正在设计一个使用Redux作为状态存储的React网站,主要是向用户显示当前的项目数量,使用实时更新来使用SignalR更新项目填充.
我想这样做的方法是让SignalR发送项目更新消息,以便在连接到服务器中心时初始化起始填充,以及随着时间的推移通过相同的消息类型进行更新.我将有一个函数,它接收SignalR消息并将其转换为Redux操作并调度到Redux存储,然后Redux存储将使用该操作来更新状态,然后更新UI.
所以这个想法是
1) Connect to SignalR server hub, with client handler function set up
for ItemUpdate messages2) When server receives Connect() from the
client, it sends ItemUpdate messages for all current items in the
population3) The client receives these messages from SignalR,
transforms to actions and dispatches to the Redux store4) Redux
updates the store based on the new item information and the UI
displays it5) Server realises an item has been added or updated and
sends a new ItemUpdate message for the update to the client6) 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启动函数的shell – 尚未实现,因为我还没有集线器和连接,并且不知道这应该去哪里
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集成,我必须将创建的商店传递给提供者组件,所以我不能把集线器创建放在这个下面,因为你需要信号器中间件组件的集线器,它被传递到商店创建
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)));