【问题标题】:Dispatch action on the callback of socket.on()对 socket.on() 回调的调度操作
【发布时间】:2017-04-12 04:58:57
【问题描述】:

所以基本上我得到了这个套接字,它可以正常工作,向我发送“新订单”消息。

我正在使用 redux,我想调度一个动作,而不是减速器会得到它并且我的商店会被更新。但是这段代码什么也没做!

socket.on('new order', (order) => {    
    return (dispatch) => {
      dispatch(socketNewOrder(order));
    }
});

这是我的操作,位于同一个文件中:

export const socketNewOrder = (order) => {
  return {
    type: 'SOCKET_NEW_ORDER',
    payload: order
  }
}

我也尝试这样调用我的操作:

socket.on('new order', (order) => {    
    socketNewOrder(order));        
});

它确实调用了这个动作,但是我的减速器没有“听到”这个动作! :(

我听说过一些关于使用中间件的事情,但我就是不知道该怎么做。

谁能解释我在接收套接字消息时如何使用中间件来调度操作,以及为什么我的代码不起作用?感谢和抱歉新手问题

【问题讨论】:

  • 您正在返回一个从未从您的套接字事件处理程序中调用的函数。你期望它做什么?而且,由于该函数从未被调用,因此您的 dispatch() 函数永远不会被调用。你的意思是这样做:socket.on('new order', (order) => { dispatch(socketNewOrder(order)); });
  • 如果我这样做,它说调度不是一个函数!
  • 那么dispatch() 是什么?
  • 直到知道,我认为调度被用来“触发”和行动

标签: sockets socket.io redux action dispatch


【解决方案1】:

这段代码应该适合你:

export const socketNewOrder = (order) => {
  return {
    type: 'SOCKET_NEW_ORDER',
    payload: order
  }
}

const handlerFunc = (dispatch) => (order) => {
    dispatch(socketNewOrder(order));
  }
});

socket.on('event', handlerFunc(dispatch));
// make sure the stores dispatch method is within scope

说明

您的事件处理函数已正确分解为一系列函数。但是这些函数的顺序是错误的。

socket.on('new order', (order) => {    
    return (dispatch) => {
      dispatch(socketNewOrder(order));
    }
});

这是构成 eventHandler 函数的系列函数的正确顺序:

socket.on('new order', (dispatch) => {    
    return (order) => {
      dispatch(socketNewOrder(order));
    }
});

以正常方式将处理程序函数绑定到套接字。

socket.on('event', handlerFunc)

所以只有在事件触发时才会调用处理函数。

如果我们需要在事件触发时调用 handlerFunc 之前绑定时将调度传递给 handlerFunc,这对我们不起作用。

但是,我们可以通过使用称为 currying 的函数式编程技术来解决这个问题,该技术允许我们将事件处理程序处理函数分解为一系列函数,这些函数可以在以后的时间点逐步调用。

柯里化是当你分解一个需要多个 参数转换为一系列函数,这些函数包含参数的一部分。

socket事件有两个重要的时间点。

  1. 处理函数绑定到套接字实例

  2. 处理函数被调用

我们可以在时间点 1 访问 Redux 存储的 dispatch 方法,但不能在时间点 2。 Currying 允许我们“存储”时间点 2 的调度方法。

所以我们可以做的是调用一个带有 dispatch 的函数来返回我们的 handlerFunction。

function handlerFunc(order){
  dispatch(socketNewOrder(order));
}

function passDispatch(dispatch){
  return handlerFunc
};

socket.on('event', passDispatch(dispatch));

因此,尽管这看起来很奇怪,但它的结果与第一个示例完全相同。通过柯里化,虽然事件处理程序将在稍后的时间点被调用,但我们仍然可以调度动作,因为我们可以访问调度变量。

我们可以使用中间件来减少每次绑定处理函数时对它们进行柯里化的重复。

【讨论】:

    【解决方案2】:

    关键是您需要在您的套接字事件侦听器中访问dispatch。使用中间件从外部事件源创建操作是一种有效的模式。

    const socketMiddleware = (store) => {
      // We have access to store, add socket listeners
      socket.on('new order', (order) => {    
        store.dispatch(socketNewOrder(order));
      });  
    
      // Actual middleware implementation just passes all
      // actions through without touching them
      return (next) => (action) => {
        next(action);
      }
    }
    

    【讨论】:

    • 这个中间件的实现对事件名称进行了硬编码。还有从哪里引用套接字实例。在存储 arg 之前将套接字实例作为参数传递给中间件调用会更好吗?
    【解决方案3】:

    示例应用程序可能会有所帮助。使用套接字更新回调列表

    SocketService.js

    import io from 'socket.io-client';
    import React from 'react';
    import { authStore } from "../../store/mobx/AuthStore"
    
    let _socket;
    let socketConnectionListeners = [];
    
    class SocketService {
    
        get socket() { return _socket; }
    
        constructor() {
            this.connect();
        }
    
        connect = async () => {
            try {
                const token = await authStore.getTokenAsync();
                if (token) {
                    _socket = io("http://localhost:8181", { query: `auth_token=${token}` });
                    await Promise.all([
                        registerSocketEvents(this.socket),
                        registerCommonEvents(this.socket)
                    ]);
                }
            } catch (error) {
                console.log('SocketService/connect/catch:', error);
            }
        }
    
        registerSocketConnectionCallBack = (callback) => {
            socketConnectionListeners.push(callback);
            return {
                remove: () => socketConnectionListeners = socketConnectionListeners.filter(c => c != callback)
            }
        }
    
        disconnect = () => {
            if (this.socket) {
                this.socket.emit('__disconnect_');
            }
        }
    }
    
    const registerSocketEvents = async (socket, path) => {
        socket.on('connect', () => console.log('socket connected'));
        socket.on('disconnect', () => console.log('socket disconnected'));
        socket.on('error', (error) => console.log('socket error', error));
    }
    
    const registerCommonEvents = async (socket) => {
        socket.on("updateCallbackList", (...data) => {
            console.log('updateCallbackList called', data);
        });
    }
    
    const SocketService = new SocketService();
    export default SocketService;
    

    回调列表功能组件

    import React, { Fragment, useEffect } from 'react';
    import { useDispatch, useSelector } from 'react-redux';
    import { fetchCallbacks } from '../../store/redux-toolkit/callback/callbackActions';
    import socketService from '../../common/services/SocketService';
    
    const CallbackList = (props) => {
    
        const dispatch = useDispatch();
        const callbackState = useSelector((state) => state.callback);
        const { loading, list } = callbackState;
    
        useEffect(() => {
            socketService.socket.on("updateCallbackList", (...data) => {
                dispatch(fetchCallbacks());
            });
            dispatch(fetchCallbacks());
        }, []);
    
        return (<Fragment></Fragment>);
    }
    
    export default CallbackList;
    

    【讨论】:

      猜你喜欢
      • 2022-10-18
      • 1970-01-01
      • 1970-01-01
      • 2013-08-13
      • 2017-11-02
      • 2018-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多