¿Cómo obtener algo del estado / tienda dentro de una función redux-saga?

121

¿Cómo accedo al estado redux dentro de una función de saga?

Respuesta corta:

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

Respuestas:

209

Como ya dice @markerikson, redux-sagaexpone una API muy útil select()para invocar un selectorestado para obtener una parte de ella disponible dentro de la saga.

Para su ejemplo, una implementación simple podría 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});
  }
}

Además del documento sugerido por @markerikson, hay un muy buen video tutorial de D. Abramov que explica cómo usar selectorsRedux. Consulta también este interesante hilo en Twitter.

NickGnd
fuente
3
Exactamente lo que quería ... No puedo creer que me lo perdí
Adam Tal
28

Para eso sirven las funciones de "selector". Les pasas todo el árbol del estado y te devuelven una parte del estado. El código que llama al selector no necesita saber en qué estado del estado estaban los datos, solo que se devolvió. Consulte http://redux.js.org/docs/recipes/ComputingDerivedData.html para ver algunos ejemplos.

Dentro de una saga, la select()API se puede utilizar para ejecutar un selector.

markerikson
fuente
Es interesante cómo se escribió 3,5 horas antes de la respuesta aceptada, pero no proporcionó un ejemplo, por lo que no fue aceptado. ¡Gracias de todos modos!
Aleksandar
1
@Casper - ¡Estoy de acuerdo! Pero no se trata de qué tan rápido responda una pregunta aquí, sino de qué tan buena es su respuesta. Creo que las respuestas deben mantenerse simples y fáciles de leer. Esta respuesta no coincidió con eso y la respuesta aceptada fue mucho más fácil de entender.
Adam Tal
@AdamTal sí, estoy de acuerdo :)
Aleksandar
2

Usé un eventChannel para enviar una acción desde una devolución de llamada dentro de la función del generador

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
fuente