gpt4 book ai didi

reactjs - React-Redux 和带有 socket.io 的 Websockets

转载 作者:行者123 更新时间:2023-12-03 13:05:42 25 4
gpt4 key购买 nike

我是 React-Redux 技术的新手,我希望您能帮助我实现一些功能。

我想用套接字实现一个聊天应用程序(socket.io)。首先,用户必须注册(我在服务器端使用 Passport),然后,如果注册成功,用户必须连接到 webSocket。

我认为最好的方法是使用像管道这样的中间件来执行所有操作,并根据获取中间件的操作类型来执行不同的操作。

如果操作类型为AUTH_USER,则创建客户端-服务器连接并设置来自服务器的所有事件。

如果操作类型是MESSAGE,则将消息发送到服务器。

代码片段:

----- socketMiddleware.js ----

import { AUTH_USER,  MESSAGE } from '../actions/types';

import * as actions from 'actions/socket-actions';

import io from 'socket.io-client';

const socket = null;

export default function ({ dispatch }) {

return next => action => {

if(action.type == AUTH_USER) {

socket = io.connect(`${location.host}`);

socket.on('message', data => {

store.dispatch(actions.addResponse(action.data));

});

}

else if(action.type == MESSAGE && socket) {

socket.emit('user-message', action.data);

return next(action)

} else {
return next(action)
}
}

}

------index.js -------

import {createStore, applyMiddleware} from 'redux';

import socketMiddleware from './socketMiddleware';



const createStoreWithMiddleware = applyMiddleware(

socketMiddleware

)(createStore);

const store = createStoreWithMiddleware(reducer);

<Provider store={store}>

<App />

</Provider>

您对这种做法有何看法?它是更好的实现吗?

最佳答案

剧透:我目前正在开发一个开源聊天应用程序。

您可以通过将操作与中间件分开,甚至将套接字客户端与中间件分开来做得更好。因此,结果是这样的:

  • 类型 -> 每个请求的 REQUEST、SUCCESS、FAILURE 类型(非强制)。
  • Reducer -> 存储不同的状态
  • 操作 -> 发送操作以连接/断开连接/发出/监听。
  • 中间件 -> 处理您的操作,并将当前操作传递或不传递给套接字客户端
  • 客户端 -> 套接字客户端 (socket.io)。

下面的代码取自正在开发的真实应用程序(有时稍加编辑),它们足以满足大多数情况,但某些东西(例如 SocketClient)可能不是 100% 完整。

操作

您希望操作尽可能简单,因为它们通常是重复的工作,并且您最终可能会遇到很多操作。

export function send(chatId, content) {
const message = { chatId, content };
return {
type: 'socket',
types: [SEND, SEND_SUCCESS, SEND_FAIL],
promise: (socket) => socket.emit('SendMessage', message),
}
}

请注意,套接字是一个参数化函数,这样我们就可以在整个应用程序中共享相同的套接字实例,并且不必担心任何导入(稍后我们将展示如何执行此操作)。

中间件(socketMiddleware.js):

我们将使用与 erikras/react-redux-universal-hot-example 类似的策略但用于套接字而不是 AJAX。

我们的套接字中间件将仅负责处理套接字请求。

中间件将操作传递到套接字客户端,并调度:

  • REQUEST(操作 types[0] ):正在请求(action.type 发送到 reducer )。
  • 成功(操作 types[1] ):请求成功(action.type 且服务器响应 action.result 发送到 reducer )。
  • FAILURE(操作 types[2] ):请求失败(action.type 和服务器响应 action.error 发送到 reducer )。
export default function socketMiddleware(socket) {
// Socket param is the client. We'll show how to set this up later.
return ({dispatch, getState}) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState);
}

/*
* Socket middleware usage.
* promise: (socket) => socket.emit('MESSAGE', 'hello world!')
* type: always 'socket'
* types: [REQUEST, SUCCESS, FAILURE]
*/
const { promise, type, types, ...rest } = action;

if (type !== 'socket' || !promise) {
// Move on! Not a socket request or a badly formed one.
return next(action);
}

const [REQUEST, SUCCESS, FAILURE] = types;
next({...rest, type: REQUEST});

return promise(socket)
.then((result) => {
return next({...rest, result, type: SUCCESS });
})
.catch((error) => {
return next({...rest, error, type: FAILURE });
})
};
}

SocketClient.js

唯一能够加载和管理 socket.io-client 的客户端。

[可选](请参阅下面的代码中的 1)。socket.io 的一个非常有趣的功能是您可以拥有 message acknowledgements ,这将是执行 HTTP 请求时的典型回复。我们可以使用它们来验证每个请求是否正确。请注意,为了使用此功能,服务器 socket.io 命令还必须具有此最新的确认参数。

import io from 'socket.io-client';

// Example conf. You can move this to your config file.
const host = 'http://localhost:3000';
const socketPath = '/api/socket.io';

export default class socketAPI {
socket;

connect() {
this.socket = io.connect(host, { path: socketPath });
return new Promise((resolve, reject) => {
this.socket.on('connect', () => resolve());
this.socket.on('connect_error', (error) => reject(error));
});
}

disconnect() {
return new Promise((resolve) => {
this.socket.disconnect(() => {
this.socket = null;
resolve();
});
});
}

emit(event, data) {
return new Promise((resolve, reject) => {
if (!this.socket) return reject('No socket connection.');

return this.socket.emit(event, data, (response) => {
// Response is the optional callback that you can use with socket.io in every request. See 1 above.
if (response.error) {
console.error(response.error);
return reject(response.error);
}

return resolve();
});
});
}

on(event, fun) {
// No promise is needed here, but we're expecting one in the middleware.
return new Promise((resolve, reject) => {
if (!this.socket) return reject('No socket connection.');

this.socket.on(event, fun);
resolve();
});
}
}

app.js

在我们的应用程序启动时,我们初始化 SocketClient并将其传递给商店配置。

const socketClient = new SocketClient();
const store = configureStore(initialState, socketClient, apiClient);

configureStore.js

我们添加socketMiddleware与我们新初始化的 SocketClient到商店中间件(还记得我们告诉过您稍后会解释的那个参数吗?)。

export default function configureStore(initialState, socketClient, apiClient) {
const loggerMiddleware = createLogger();
const middleware = [
...
socketMiddleware(socketClient),
...
];

[没什么特别的]操作类型常量

没什么特别的=你通常会做的事情。

const SEND = 'redux/message/SEND';
const SEND_SUCCESS = 'redux/message/SEND_SUCCESS';
const SEND_FAIL = 'redux/message/SEND_FAIL';

[没什么特别的] reducer

export default function reducer(state = {}, action = {}) {
switch(action.type) {
case SEND: {
return {
...state,
isSending: true,
};
}
default: {
return state;
}
}
}

这可能看起来需要大量工作,但一旦设置完毕,一切都是值得的。您的相关代码将更易于阅读、调试,并且您将更不容易犯错误。

PS:您也可以通过 AJAX API 调用遵循此策略。

关于reactjs - React-Redux 和带有 socket.io 的 Websockets,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37876889/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com