getState in redux-saga?
Asked Answered
F

3

95

I have a store with a list of items. When my app first loads, I need to deserialize the items, as in create some in-memory objects based on the items. The items are stored in my redux store and handled by an itemsReducer.

I'm trying to use redux-saga to handle the deserialization, as a side effect. On first page load, I dispatch an action:

dispatch( deserializeItems() );

My saga is set up simply:

function* deserialize( action ) {
    // How to getState here??
    yield put({ type: 'DESERISLIZE_COMPLETE' });
}

function* mySaga() {
    yield* takeEvery( 'DESERIALIZE', deserialize );
}

In my deserialize saga, where I want to handle the side effect of creating in-memory versions of my items, I need to read the existing data from the store. I'm not sure how to do that here, or if that's a pattern I should even be attempting with redux-saga.

Frisbie answered 15/7, 2016 at 22:14 Comment(1)
why do you want to read the data from the store ? can't you just pass the data in the action payload ?Finny
T
255

you can use select effect

import {select, ...} from 'redux-saga/effects'

function* deserialize( action ) {
    const state = yield select();
    ....
    yield put({ type: 'DESERIALIZE_COMPLETE' });
}

also you can use it with selectors

const getItems = state => state.items;

function* deserialize( action ) {
    const items = yield select(getItems);
    ....
    yield put({ type: 'DESERIALIZE_COMPLETE' });
}
Thomas answered 16/7, 2016 at 6:20 Comment(0)
M
3

In addition to the answer from @Kokovin Vladislav, if we like to use typing of Typescript, we could use "defined typed hooks" pattern introduced by redux-toolkit on this doc: https://redux-toolkit.js.org/tutorials/typescript#define-typed-hooks.

So, in the app/hooks.ts file we have:

import { useDispatch, useSelector } from 'react-redux'
import type { TypedUseSelectorHook } from 'react-redux'
import type { RootState, AppDispatch } from './store'

import { select } from 'redux-saga/effects'

// Use throughout your app instead of plain `useDispatch` and `useSelector` ( From redux-toolkit docs )
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector

// THIS IS THE ADDITIONAL SELECTOR!!!!!!!
export function* appSelect<TSelected>( selector: (state: RootState) => TSelected, ): Generator<any, TSelected, TSelected> { return yield select(selector); }

Then in your generator function, you could do similar like this:

import { appSelect } from "app/hooks"

function* deserialize( action ) {
    const items = yield* appSelect(state => state.items);
    ....
    yield put({ type: 'DESERIALIZE_COMPLETE' });
}

That way we have strong typing and intelisense of state on each call of appSelect().

Credit: https://github.com/redux-saga/redux-saga/issues/970#issuecomment-880799390

Matlock answered 30/11, 2022 at 10:20 Comment(0)
C
-7

Select effect does not help us if we in a callback functions, when code flow is not handled by Saga. In this case just pass dispatch and getState to root saga:

store.runSaga(rootSaga, store.dispatch, store.getState)

And the pass parameters to child sagas

export default function* root(dispatch, getState) { yield all([ fork(loginFlow, dispatch, getState), ]) }

And then in watch methods

export default function* watchSomething(dispatch, getState) ...

Conlen answered 26/9, 2017 at 13:8 Comment(2)
This seems more like an anti-pattern. Redux saga is middleware already and shouldn't need something this kludgy. What is a callback function not handled by a saga? How does passing something INTO the saga help something that is not handled by the saga?Vaisya
I do not agree. yield select() is only applicable at saga context. Only. Saga can involve some functions, other libraries with user interactions via callbacks. By that time when callback fired - saga may not present at all. This is a way how to use Store, when Saga is out. (for example frontend microservices, web-component approach with multiple stores, saga, react and so on)Conlen

© 2022 - 2024 — McMap. All rights reserved.