Реагировать-Redux и веб-сокетов с гнездом.Ио
Я новичок в этой технологии React-Redux, и я хотел бы получить вашу помощь в некоторой реализации.
Я хочу реализовать одно приложение чата с сокетами (socket.io). Во-первых, пользователь должен зарегистрироваться (я использую паспорт на стороне сервера), а после, если регистрация успешна, пользователь должен подключиться к 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)
}
}
}
------ индекс.js -------
import {createStore, applyMiddleware} from 'redux';
import socketMiddleware from './socketMiddleware';
const createStoreWithMiddleware = applyMiddleware(
socketMiddleware
)(createStore);
const store = createStoreWithMiddleware(reducer);
<Provider store={store}>
<App />
</Provider>
что вы думаете об этой практике, это лучше реализации?
1 ответов
спойлер: в настоящее время я разрабатываю то, что будет приложением чата с открытым исходным кодом.
вы можете сделать это лучше отделять действия от промежуточного, и даже сокет клиента с middleware. Следовательно, в результате чего-то вроде этого:
- типы - > запрос, успех, типы сбоев для каждого запроса (не обязательно).
- редуктор - > для того чтобы хранить различное государства
- действия - > отправить действия для подключения / отключения / излучения / прослушивания.
- промежуточное ПО - > чтобы обработать ваши действия и передать или не передать текущее действие клиенту сокета
- клиент - > клиент сокета (сокет.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-универсальный-горячий-пример использует, хотя для сокета вместо AJAX.
наше промежуточное ПО сокета будет отвечать за обработку только запросов сокета.
промежуточное ПО передает действие на клиент сокета и отправляет:
- запрос (действие
types[0]
): запрашивает (action.type
отправлено редуктор). - успех (действие
types[1]
): по запросу success (action.type
и ответ сервера какaction.result
отправлено редуктор). - отказ (действие
types[2]
): по запросу недостаточности (action.type
и ответ сервера какaction.error
отправляются в редуктор).
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
единственный, который будет когда-либо загружать и управлять розетка.io-клиент.
[необязательно] (см. 1 ниже в коде). одна очень интересная особенность о сокете.io-это тот факт, что вы можете иметь подтверждение сообщения, что было бы типичными ответами при выполнении HTTP-запроса. Мы можем использовать их для проверки правильности каждого запроса. Обратите внимание, что для использования этого сокета сервера функций.команды ввода-вывода также должны иметь это последнее подтверждение параметр.
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
в магазин middlewares (помните тот параметр, который мы сказали вам, что мы объясним позже?).
export default function configureStore(initialState, socketClient, apiClient) {
const loggerMiddleware = createLogger();
const middleware = [
...
socketMiddleware(socketClient),
...
];
[ничего особенного] типы действий константы!--20-->
ничего особенного = то, что вы обычно делаете.
const SEND = 'redux/message/SEND';
const SEND_SUCCESS = 'redux/message/SEND_SUCCESS';
const SEND_FAIL = 'redux/message/SEND_FAIL';
[ничего особенного] редуктор
export default function reducer(state = {}, action = {}) {
switch(action.type) {
case SEND: {
return {
...state,
isSending: true,
};
}
default: {
return state;
}
}
}
это может выглядеть как много работы, но, как только вы установите его, оно того стоит. Ваш код будет легче читать, отлаживать и вы будете менее склонны делать ошибки.
PS: вы также можете следовать этой стратегии с вызовами AJAX API.