Реагировать-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.