最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using put inside anonymous function callback - Stack Overflow

programmeradmin10浏览0评论

I am implementing Pusher into my React+Redux Saga application, but I am having a few problems with some callbacks where I can not hit the put(...) methods. Using console.log(...) etc. in the methods does show, but I am not able to put to the state of my application.

I could be wrong on some of the implementation of async/generator functions, but I am pretty much stuck right now.

My code to illustrate what will not fire:

import { takeLatest } from 'redux-saga'
import { call, put } from 'redux-saga/effects'

// Pusher actions
export const pusherConnecting = () => {
    return {
        type: ActionTypes.PUSHER_CONNECTING
    }
};

export const pusherConnectSucceeded = (client) => {
    return {
        type: ActionTypes.PUSHER_CONNECT_SUCCEEDED,
        client: client
    }
};

const pusherConnectFailed = (exception) => {
    return {
        type: ActionTypes.PUSHER_CONNECT_FAILED,
        message: exception
    }
};

// Pusher Saga
function * connectPusher(action) {
    try {
        const pusher = yield call(Api.connectPusher, action.directory, function(subscription) {
            subscription.bind(PUSHER_BIND_RELOAD, function() {
                location.reload(true);
            });

            subscription.bind(PUSHER_BIND_REQUEST_DATA, function(data) {
                if (data) {
                    put(updateDirectory(data));
                } else {
                    put(requestDirectory(action.directory.id));
                }
            });
        });

        pusher.connection.bind('connected', function() {
            put(pusherConnectSucceeded(pusher));
        });

        yield put(pusherConnecting());

    } catch (e) {
        yield put(pusherConnectFailed(e));
    }
}

export default function * pusherSaga() {
    yield * takeLatest(ActionTypes.DIRECTORY_FETCH_SUCCEEDED, connectPusher);
}



// My Api.ConnectPusher
export function * connectPusher(directory, subscription) {
    var pusher = new Pusher(PUSHER_KEY, {
        encrypted: true
    });

    var channels = ["test1", "test2"  ];

    for (var i = 0; i < channels.length; i++) {
        // Take each channel and callback with the subscription
        yield subscription(pusher.subscribe(channels[i]));
    }

    return pusher;
}

Solution based on @Sebastien

yield put(yield onConnect(pusher));

function onConnect(pusher) {
    return new Promise((resolve, reject) => {
        pusher.connection.bind('connected', function() {
            resolve(pusherConnectSucceeded(pusher));
        });
    });
}

I am implementing Pusher into my React+Redux Saga application, but I am having a few problems with some callbacks where I can not hit the put(...) methods. Using console.log(...) etc. in the methods does show, but I am not able to put to the state of my application.

I could be wrong on some of the implementation of async/generator functions, but I am pretty much stuck right now.

My code to illustrate what will not fire:

import { takeLatest } from 'redux-saga'
import { call, put } from 'redux-saga/effects'

// Pusher actions
export const pusherConnecting = () => {
    return {
        type: ActionTypes.PUSHER_CONNECTING
    }
};

export const pusherConnectSucceeded = (client) => {
    return {
        type: ActionTypes.PUSHER_CONNECT_SUCCEEDED,
        client: client
    }
};

const pusherConnectFailed = (exception) => {
    return {
        type: ActionTypes.PUSHER_CONNECT_FAILED,
        message: exception
    }
};

// Pusher Saga
function * connectPusher(action) {
    try {
        const pusher = yield call(Api.connectPusher, action.directory, function(subscription) {
            subscription.bind(PUSHER_BIND_RELOAD, function() {
                location.reload(true);
            });

            subscription.bind(PUSHER_BIND_REQUEST_DATA, function(data) {
                if (data) {
                    put(updateDirectory(data));
                } else {
                    put(requestDirectory(action.directory.id));
                }
            });
        });

        pusher.connection.bind('connected', function() {
            put(pusherConnectSucceeded(pusher));
        });

        yield put(pusherConnecting());

    } catch (e) {
        yield put(pusherConnectFailed(e));
    }
}

export default function * pusherSaga() {
    yield * takeLatest(ActionTypes.DIRECTORY_FETCH_SUCCEEDED, connectPusher);
}



// My Api.ConnectPusher
export function * connectPusher(directory, subscription) {
    var pusher = new Pusher(PUSHER_KEY, {
        encrypted: true
    });

    var channels = ["test1", "test2"  ];

    for (var i = 0; i < channels.length; i++) {
        // Take each channel and callback with the subscription
        yield subscription(pusher.subscribe(channels[i]));
    }

    return pusher;
}

Solution based on @Sebastien

yield put(yield onConnect(pusher));

function onConnect(pusher) {
    return new Promise((resolve, reject) => {
        pusher.connection.bind('connected', function() {
            resolve(pusherConnectSucceeded(pusher));
        });
    });
}
Share Improve this question edited Jun 9, 2016 at 13:21 janhartmann asked Jun 9, 2016 at 11:13 janhartmannjanhartmann 15k17 gold badges87 silver badges140 bronze badges 5
  • What does "is not hit" mean? You don't reach that line? How are you checking, with a debugger? – T.J. Crowder Commented Jun 9, 2016 at 11:23
  • It means that I am unable to fire this method. The putmethod is not invoked in my anonymous method callback. Or maybe it is, but the state is not changing (which is my my question). – janhartmann Commented Jun 9, 2016 at 11:23
  • Why "maybe"? It seems like that would be a really fundamental thing to determine, whether put is not being reached or being reached but not having the desired effect. I'd use a debugger to follow what, exactly, happens, or (and this is very much a second-class option) throw in some console.logs. (But pared to wandering about with a console.log torch, using a debugger is like turning on the lights.) – T.J. Crowder Commented Jun 9, 2016 at 11:28
  • My problem is that e.g. the put(pusherConnectSucceeded(pusher)); method does not dispatch a state change. Apperently it is not possible to call put(...) inside an anonymous callback. – janhartmann Commented Jun 9, 2016 at 11:48
  • No, there's no way for put to know you're calling it from an anonymous callback, and even if there were, there's nothing special about anonymous callbacks. Again, you'll just need to debug this. – T.J. Crowder Commented Jun 9, 2016 at 11:53
Add a ment  | 

1 Answer 1

Reset to default 8

Redux-saga does not permit to put without using keyword yield. The put creates a simple json object/effect that must be interpreted/executed, and it won't if you don't yield.

Also, even with yield put(...), if this is done in a callback, it won't be interpreted, because Redux-saga does not have the ability to run callbacks in its interpreter. They'll simply be run as normal callbacks and nothing will happen.

If subscription.bind is supposed to return a single result, you can instead wrap that call into a function that returns a promise, and then yield that promise.

If subscription.bind is supposed to return a stream of results, you might need instead of create a channel. I guess in the future someone will ship something that can easily permits to transform Observables to Redux-saga streams

Note that if you don't need to unsubscribe/resubscribe multiple times, it may be simpler to you to put this code outside the saga, and just do

        subscription.bind(PUSHER_BIND_RELOAD, function() {
            location.reload(true);
        });

        subscription.bind(PUSHER_BIND_REQUEST_DATA, function(data) {
            if (data) {
                reduxStore.dispatch(updateDirectory(data));
            } else {
                reduxStore.dispatch((requestDirectory(action.directory.id));
            }
        });
发布评论

评论列表(0)

  1. 暂无评论