Como obter algo do estado / loja dentro de uma função redux-saga?

121

Como faço para acessar o estado redux dentro de uma função saga?

Resposta curta:

import { select } from 'redux-saga/effects';
...
let data = yield select(stateSelectorFunction);
Adam Tal
fonte

Respostas:

209

Como @markerikson já diz, redux-sagaexpõe uma API muito útil select()para invocar um selectoron the state para obter alguma parte dele disponível dentro da saga.

Para seu exemplo, uma implementação simples poderia ser:

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

Além do documento sugerido por @markerikson, há um vídeo tutorial muito bom de D. Abramov que explica como usar selectorscom o Redux. Verifique também este tópico interessante no Twitter.

NickGnd
fonte
3
Exatamente o que eu queria .. Não posso acreditar que perdi
Adam Tal
28

É para isso que servem as funções de "seletor". Você passa para eles toda a árvore de estado e eles retornam alguma parte do estado. O código que chama o selector não precisa saber onde no estado que os dados foi, apenas que ele foi devolvido. Veja http://redux.js.org/docs/recipes/ComputingDerivedData.html para alguns exemplos.

Dentro de uma saga, a select()API pode ser usada para executar um seletor.

marcadorikson
fonte
É interessante como isso foi escrito 3,5 horas antes da resposta aceita, mas não fornecia um exemplo, então não foi aceito. Obrigado de qualquer maneira!
Aleksandar de
1
@Casper - eu concordo! Mas não se trata de quão rápido você responde a uma pergunta aqui, mas de quão boa é sua resposta. Acho que as respostas devem ser simples e fáceis de ler. Essa resposta não correspondeu a isso e a resposta aceita foi muito mais fácil de entender.
Adam Tal
@AdamTal sim, concordo :)
Aleksandar
2

Eu usei um eventChannel para despachar uma ação de um retorno de chamada dentro da função do gerador

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
fonte