Использование функции возврата анонимной функции

Я реализую Pusher в приложении React + Redux Saga, но у меня есть несколько проблем с некоторыми обратными вызовами, где я не могу попасть в put(...). Использование console.log(...) и т.д. В методах действительно показывает, но я не могу put указать состояние моего приложения.

Я могу ошибаться в некоторых реализациях функций async/generator, но сейчас я довольно сильно застрял.

Мой код, чтобы проиллюстрировать, что не будет срабатывать:

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;
}

Решение, основанное на @Sebastien

yield put(yield onConnect(pusher));

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

Ответ 1

Redux-сага не позволяет put без использования ключевого слова yield. Помещение создает простой json-объект/эффект, который должен быть интерпретирован/выполнен, и он не будет, если вы не уступите.

Кроме того, даже при yield put(...), если это сделано в обратном вызове, это не будет интерпретироваться, потому что у Redux-саги нет возможности запускать обратные вызовы в его интерпретаторе. Они просто будут работать как обычные обратные вызовы, и ничего не произойдет.

Если subscription.bind должен возвращать единственный результат, вы можете вместо этого перевести этот вызов в функцию, которая возвращает обещание, а затем дать это обещание.

Если subscription.bind должен возвращать поток результатов, вам может понадобиться вместо channel. Я предполагаю, что в будущем кто-то отправит что-то, что может легко разрешить преобразование Observables в потоки Redux-saga

Обратите внимание, что если вам не нужно отменить подписку/повторную подписку несколько раз, вам может быть проще разместить этот код вне саги и просто сделать

        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));
            }
        });