NZJ*_*mes 5 javascript signalr reactjs redux
我正在设计一个使用Redux作为状态存储的React网站,该网站主要是为了向用户显示项目的当前填充,并使用实时更新通过SignalR更新项目填充。
我要这样做的方法是让SignalR发送项目更新消息,以在连接到服务器集线器时初始化初始填充,并随着时间的流逝通过相同的消息类型进行更新。我将有一个函数,该函数接受SignalR消息并将其转换为Redux动作并调度到Redux商店,然后该商店将使用该动作来更新状态,然后更新UI。
所以这个想法是
1)连接到SignalR服务器中心,并为ItemUpdate消息设置客户端处理程序功能
2)当服务器从客户端收到Connect()时,它将为填充中的所有当前项目发送ItemUpdate消息
3)客户端从SignalR接收这些消息,转换为动作并调度到Redux存储
4)Redux根据新商品信息更新商店,UI会显示它
5)服务器意识到一个项目已被添加或更新,并向客户端发送新的ItemUpdate消息以进行更新
6)重复
但是我不确定应该将集线器保持在什么位置,因为这似乎与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();
Run Code Online (Sandbox Code Playgroud)
我的商店创建文件
import { createStore, applyMiddleware } from 'redux';
import rootReducer from '../reducers/index';
import signalRMiddleware from '../signalr/middleware';
const store = createStore(rootReducer, applyMiddleware(signalRMiddleware));
export default store;
Run Code Online (Sandbox Code Playgroud)
我的中间件,用于向服务器发送出站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);
}
}
Run Code Online (Sandbox Code Playgroud)
现在对于传入的消息...这是我从在线示例中获得的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());
}
Run Code Online (Sandbox Code Playgroud)
这是网站上给出的示例,我找到了将其绑定在一起的代码,但是我没有看到它如何与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"));
});
Run Code Online (Sandbox Code Playgroud)
有人可以建议将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;
Run Code Online (Sandbox Code Playgroud)
在我的store.js文件中
import signalRMiddleware from '../middlewares/signalRMiddleware';
...
createStore(rootReducer, {}, composeEnhancers(applyMiddleware(signalRMiddleware)));
Run Code Online (Sandbox Code Playgroud)
根据 Redux FAQ,websockets 和其他类似连接的正确位置是 Redux 中间件。
这是现有 websocket 中间件的列表。您可以查看其中几个的源代码,并很容易地了解如何实现您自己的自定义中间件:
中间件可以分派动作。这是一个套接字中间件可能是什么样子的示例,并分派它侦听的操作:
const createMySocketMiddleware = (url) => {
return storeAPI => {
let socket = createMyWebsocket(url);
socket.on("message", (message) => {
storeAPI.dispatch({
type : "SOCKET_MESSAGE_RECEIVED",
payload : message
});
});
return next => action => {
if(action.type == "SEND_WEBSOCKET_MESSAGE") {
socket.send(action.payload);
return;
}
return next(action);
}
}
}
Run Code Online (Sandbox Code Playgroud)
您需要将此中间件应用到您的 redux 商店
let store = createStore(
some_reducer,
applyMiddleware(createMySocketMiddleware)
)
Run Code Online (Sandbox Code Playgroud)
稍后,在您的应用程序中。这是一个动作创建者
const sendSocketMessage = message => ({
type : "SEND_WEBSOCKET_MESSAGE",
payload : message
}
Run Code Online (Sandbox Code Playgroud)
在你的组件中添加一个按钮以通过 websockets 调度一个动作
class MyComponent extends React.Component {
handleClick = () => {
this.props.sendSocketMessage("This goes to the server");
}
}
export default connect(null, {sendSocketMessage})(MyComponent)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4926 次 |
| 最近记录: |