【问题标题】:Reusing websocket connection object in Redux Saga在 Redux Saga 中重用 websocket 连接对象
【发布时间】:2021-09-16 04:57:18
【问题描述】:

我有问题。我在 React Redux eventChannel 中的 websocket 的帮助下连接到服务器。我从服务器接收事件没有问题,但我无法将事件发送到服务器。我知道,我需要获取我在 eventChannel 中创建的 websocket 连接对象,以从反应组件发送事件。

export function* wsWatcher() {
    yield takeEvery("LOGIN_SUCCESS", wsConnectionWorker);
}

function* wsConnectionWorker() {
    const channel: EventChannel<boolean> = yield call(initWebsocket);
    while (true) {
        const action: Action<any> = yield take(channel);
        yield put(action);
    }
}

function initWebsocket(): EventChannel<any> {
    return eventChannel((emitter) => {

    let id: string | undefined;
    let intervalId: number;

    const initConnection = () => {
        const connectionUrl: string = "ws://localhost:4000" 
            
        let ws = new WebSocket(connectionUrl);
        
        ws.onopen = () => {
            id && ws.send(JSON.stringify({ type: "GET_USER_ID", id }));

            intervalId = window.setInterval(() => {
                ws.send(JSON.stringify({ type: "PING" }))
            }, 30000)
        };

        ws.onclose = (e) => {
            console.log("Reconnect in 4s");
            intervalId && clearInterval(intervalId);
            id && setTimeout(initConnection, 4000); 
        };
    };

    initConnection();

    return () => {
        console.log("Socket off");
    };
});
}

提前致谢

【问题讨论】:

    标签: javascript reactjs redux websocket redux-saga


    【解决方案1】:

    您可以在模块的范围内创建一个变量,并在第一次初始化后将连接对象存储在其中。以后需要连接时,只需使用此变量即可。

    这是可行的,因为模块缓存在 nodejs 中。也就是说,模块中的代码仅在首次导入时运行,以后导入使用缓存的模块。

    如需进一步参考,请阅读更多:Modules Caching

    您也可以为此设置一个函数,例如此代码中的getConnection 函数。每当您需要 websocket 连接时,调用此函数,它只会创建一次连接。

    export function* wsWatcher() {
        yield takeEvery("LOGIN_SUCCESS", wsConnectionWorker);
    }
    
    function* wsConnectionWorker() {
        const channel: EventChannel<boolean> = yield call(getConnection);
        while (true) {
            const action: Action<any> = yield take(channel);
            yield put(action);
        }
    }
    
    // store the EventChannel after first init
    let wsConnection: EventChannel<any> = null;
    
    // create WS connection on first call
    // reuse that connection in further calls
    function getConnection(): EventChannel<any>{
      if(!wsConnection){
        wsConnection = initWebsocket();
      return wsConnection;
    }
    
    function initWebsocket(): EventChannel<any> {
        return eventChannel((emitter) => {
    
        let id: string | undefined;
        let intervalId: number;
    
        const initConnection = () => {
            const connectionUrl: string = "ws://localhost:4000" 
                
            let ws = new WebSocket(connectionUrl);
            
            ws.onopen = () => {
                id && ws.send(JSON.stringify({ type: "GET_USER_ID", id }));
    
                intervalId = window.setInterval(() => {
                    ws.send(JSON.stringify({ type: "PING" }))
                }, 30000)
            };
    
            ws.onclose = (e) => {
                console.log("Reconnect in 4s");
                intervalId && clearInterval(intervalId);
                id && setTimeout(initConnection, 4000); 
            };
        };
    
        initConnection();
    
        return () => {
            console.log("Socket off");
        };
    });
    }
    

    【讨论】:

    • 嗨!感谢您的回答。但我很困惑。当我导入 wsConnection 时,我有一个具有以下属性的对象:take、flush 和 close。我认为,它的 redux 传奇属性。我可以保存一个“ws”对象吗,我在这里得到:“let ws = new WebSocket(connectionUrl);”?
    • 你可以。但是,如果您使用缓存的 WebSocket,则在向其中添加 onopenonclose 事件侦听器时应该小心,因为这些事件侦听器可能已经存在。
    • 所以我创建了一个全局变量,将 ws 变量保存到它并导出它?然后我可以导入它并使用我想要的方式?
    • 是的,创建一个全局变量,最好也是一个函数getWs()getWs 应该返回已经可用的实例或创建一个并返回。在这种情况下,您将不得不更改 onopenonclose 逻辑。如果你能分享你想通过这个传奇实现的目标,我会修改我的代码。
    • 我创建了一个变量,并在“let ws = new WebSocket()”字符串之后将 ws 对象保存到其中。例如,我现在可以导入它并在我的点击事件中使用它。我想要的是从我的反应组件访问 ws 以便将事件发送到服务器。创建全局变量有一点问题。如果我在组件内部使用这个变量(不在事件处理程序或其他东西中),它会说它仍处于连接状态。但在处理程序中一切都很好
    猜你喜欢
    • 2020-01-21
    • 1970-01-01
    • 1970-01-01
    • 2020-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多