Search code examples
reactjsreduxsocket.ioredux-sagalaravel-echo

Redux saga not dispatching action on live sockets


I am trying dispatch an action whenever a response appear on live socket using redux-saga. I have been able to reach to the line of code where action should be put(dispatched) but only in this live sockets case live actions are not dispatching.

Here is my code:

export function* watchEditorAcceptInvitatioRequest(action) {
    yield takeEvery(START_EDITOR_ACCEPT_INVITATION_SOCKET, edditorAcceptInvitationSocket)
}

export function* edditorAcceptInvitationSocket(action) {
    const {token, user_id} = action.payload
    const subscription = SocketIo.subscribe(token, '/broadcasting/authTest')

    yield put(listenEditorAcceptInvitationSocket())
    let result = yield call(SocketIo.listen, subscription, `new-test-channel.${user_id}`,
        '.new-test-test', (response) => edditorAcceptInvitationReceived({
            func: receiveEditorAcceptInvitationSocket,
            response: response
        }))

}

export function* edditorAcceptInvitationReceived(action) {
    while(true) {

        console.log(action.response) // I am seeing this in response but the action put in blow line
        yield put(action.func(action.response))
    }
}

Below is socket subscription and listening code:

import Echo from 'laravel-echo'
import Socketio from 'socket.io-client'

const BASE_URL = 'https://www.my domain.com'
const PORT = 1111

const subscribe = (token, authEndpoint) => new Echo({
    broadcaster: 'socket.io',
    host: `${BASE_URL}:${PORT}`,
    client: Socketio,
    authEndpoint: authEndpoint,
    auth: {
        headers: {
            Authorization: 'Bearer ' + token,
            Accept: 'application/json',
        },
    },
})

const listen = (echo, channel, event, callback) => {
    echo.private(channel).listen(event, e => {
        const generator = callback(e)
        generator.next()
    })
}

export default {
    subscribe,
    listen
}

What is missing here, Any help will be appreciated.


Solution

  • I was able to solve this issue with eventChannel

    Working code for above example is:

    export function* watchEditorAcceptInvitatioRequest(action) {
        yield takeEvery(START_EDITOR_ACCEPT_INVITATION_SOCKET, edditorAcceptInvitationSocket)
    }
    
    export function* edditorAcceptInvitationSocket(action) {
        const {token, user_id} = action.payload
        const subscription = SocketIo.subscribe(token, '/broadcasting/authTest')
        yield put(listenEditorAcceptInvitationSocket())
        let channel = yield call(SocketIo.listen, subscription, `new-test-channel.${user_id}`,
            '.new-test-test', receiveEditorAcceptInvitationSocket)
        while (true) {
            const action = yield take(channel)
            yield put(action)
        }
    }
    

    Below is updated socket subscription and listening code:

    import store from '../store/configureStore' import Echo from 'laravel-echo' import Socketio from 'socket.io-client' import {eventChannel} from 'redux-saga'

    const BASE_URL = 'https://www.my domain.com'
    const PORT = 1111
    
    const subscribe = (token, authEndpoint) => new Echo({
        broadcaster: 'socket.io',
        host: `${BASE_URL}:${PORT}`,
        client: Socketio,
        authEndpoint: authEndpoint,
        auth: {
            headers: {
                Authorization: 'Bearer ' + token,
                Accept: 'application/json',
            },
        },
    })
    
    const listen = (echo, channel, event, callback) => {
        return eventChannel( emitter => {
            echo.private(channel).listen(event, e => {
                emitter(store.dispatch(callback(e)))
            })
            return () => {
                console.log('returning channel')
            }
        })}
    
    export default {
        subscribe,
        listen
    }