Как получить что-то из состояния / магазина внутри функции redux-saga?

123

Как мне получить доступ к состоянию редукции внутри функции саги?

Короткий ответ:

import { select } from 'redux-saga/effects';
...
let data = yield select(stateSelectorFunction);
Адам Тал
источник

Ответы:

211

Как уже сказал @markerikson, redux-sagaпредоставляет очень полезный API select()для вызова selectorсостояния, чтобы часть его была доступна внутри саги.

Для вашего примера простая реализация может быть:

/*
 * Selector. The query depends by the state shape
 */
export const getProject = (state) => state.project

// Saga
export function* saveProjectTask() {
  while(true) {
    yield take(SAVE_PROJECT);
    let project = yield select(getProject); // <-- get the project
    yield call(fetch, '/api/project', { body: project, method: 'PUT' });
    yield put({type: SAVE_PROJECT_SUCCESS});
  }
}

В дополнение к предложенному документу @markerikson есть очень хороший видеоурок от Д. Абрамова, в котором объясняется, как использовать selectorsс Redux. Также проверьте эту интересную ветку в Twitter.

NickGnd
источник
3
Это именно то, что я хотел ... Не могу поверить, что я это пропустил
Адам Тал
30

Вот для чего нужны "селекторные" функции. Вы передаете им все дерево состояний, и они возвращают некоторую часть состояния. Код , который вызывает селектор не нужно знать , где в состоянии , что данные были, только что он был возвращен. См. Http://redux.js.org/docs/recipes/ComputingDerivedData.html для некоторых примеров.

В саге select()API можно использовать для выполнения селектора.

markerikson
источник
Интересно, как это было написано за 3,5 часа до принятого ответа, но в нем не было примера, поэтому он не был принят. В любом случае спасибо!
Aleksandar
1
@Casper - согласен! Но дело не в том, как быстро вы отвечаете на вопрос, а в том, насколько хорош ваш ответ. Я считаю, что ответы должны быть простыми и удобными для чтения. Этот ответ не соответствовал этому, и принятый ответ было намного легче понять.
Adam Tal
@AdamTal да, согласен :)
Aleksandar
2

Я использовал eventChannel для отправки действия из обратного вызова в функции генератора

import {eventChannel} from 'redux-saga';
import {call, take} from 'redux-saga/effects';

function createEventChannel(setEmitter) {
    return eventChannel(emitter => {
        setEmitter(emitter)
        return () => {

        }
      }
    )
}

function* YourSaga(){
    let emitter;
    const internalEvents = yield call(createEventChannel, em => emitter = em)

    const scopedCallback = () => {
        emitter({type, payload})
    }

    while(true){
        const action = yield take(internalEvents)
        yield put(action)
    }
}
yardenapp
источник