Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 使用socket.io响应Redux和Websockets_Reactjs_Socket.io_Redux_Middleware - Fatal编程技术网

Reactjs 使用socket.io响应Redux和Websockets

Reactjs 使用socket.io响应Redux和Websockets,reactjs,socket.io,redux,middleware,Reactjs,Socket.io,Redux,Middleware,我对React Redux这项技术是新手,我希望您能帮助我实现一些功能 我想用socket(socket.io)实现一个聊天应用程序。首先,用户必须注册(我在服务器端使用passport),然后,如果注册成功,用户必须连接到webSocket 我认为最好的方法是使用一个中间件,比如一个管道来执行所有的操作,并且根据什么样的操作得到中间件,做不同的事情 如果操作类型为AUTH_USER,则创建客户机-服务器连接并设置将来自服务器的所有事件 如果操作类型为MESSAGE则将消息发送到服务器 代码片段

我对React Redux这项技术是新手,我希望您能帮助我实现一些功能

我想用socket(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)
        }
    }

}
import {createStore, applyMiddleware} from 'redux';

import socketMiddleware from './socketMiddleware';



const createStoreWithMiddleware = applyMiddleware(

  socketMiddleware

)(createStore);

const store = createStoreWithMiddleware(reducer);

<Provider store={store}>

    <App />

</Provider>
----index.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)
        }
    }

}
import {createStore, applyMiddleware} from 'redux';

import socketMiddleware from './socketMiddleware';



const createStoreWithMiddleware = applyMiddleware(

  socketMiddleware

)(createStore);

const store = createStoreWithMiddleware(reducer);

<Provider store={store}>

    <App />

</Provider>
从'redux'导入{createStore,applyMiddleware};
从“/socketMiddleware”导入socketMiddleware;
const createStoreWithMiddleware=applyMiddleware(
socketMiddleware
)(createStore);
const store=createStoreWithMiddleware(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),
  }
}
请注意,socket是一个参数化函数,这样我们就可以在整个应用程序中共享同一个socket实例,而不必担心任何导入问题(稍后我们将演示如何实现)

中间件(socketMiddleware.js):

我们将使用与uses类似的策略,不过对于socket而不是AJAX

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

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

  • 请求(操作
    types[0]
    ):正在请求(
    action.type
    被发送到reducer)
  • 成功(操作
    类型[1]
    ):请求成功(
    action.type
    ,服务器响应为
    action.result
    发送到reducer)
  • 失败(操作
    类型[2]
    ):请求失败(将
    操作.type
    和服务器响应作为
    操作.error
    发送到reducer)
SocketClient.js

唯一一个将加载和管理socket.io-client的客户端

[可选](请参见代码中的下面1)。关于socket.io的一个非常有趣的特性是,您可以拥有,这将是执行HTTP请求时的典型回复。我们可以使用它们来验证每个请求是否正确。请注意,为了使用此功能,server 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

我们使用新初始化的
SocketClient
socketMiddleware
添加到存储中间件(还记得我们告诉过您稍后将解释的参数吗?)

[Nothing special]动作类型常量

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

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调用遵循此策略。

为此,我使用了来自的函数。它自动生成类型,如
挂起
完成
拒绝

我在他的回答中使用了与@zurfyx相同的socketService

操作如下所示:

const sendMessage=createAsyncThunk(
“游戏/发送消息”,
异步函数(文本,{getState}){
const roomToken=selectRoomToken(getState());
return wait-socketService.emit('send-message',{text,roomToken});
}
);
减速器看起来像这样:

const gameSlice=createSlice({
名称:'游戏',
初始状态:{},
还原子:{},
外减速器:{
[sendMessage.pending]:(状态、操作)=>{
state.messages.push({
id:action.meta.requestId,
文本:action.meta.arg,
我的朋友:是的,
});
},
[sendMessage.rejected]:(状态、操作)=>{
state.messages=state.messages.filter(
ms=>ms.id!==action.meta.requestId
);
},
},
});

一般来说,这类问题不适合stackoverflow,但您的方法看起来是合理的。唯一让我感到“奇怪”的是有条件地调用
next(action)
。通常,您希望调用下一个中间件(dispatcher),例如,让它处理日志记录或您可能在那里拥有的任何其他内容