Использование функции возврата анонимной функции
Я реализую 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));
}
});