Proposal: Parametric sagas
See original GitHub issueI’ve run into following problem:
Suppose we have two sagas: one daemon, and one call
able:
function *daemonSaga() {
while (true) {
const action = take(...);
yield call(callableSaga, action.payload);
}
}
function *callableSaga(params) {
// ...
}
Now, suppose that callableSaga
becomes dependent on state (in my particular case it depends on locale setting that is stored in the state). We could use getState()
in daemonSaga
and pass extra state data to callableSaga
, but that’s not very convenient: if there is another dependency in callableSaga
, we’d have to change code of daemonSaga
again; also, if there is another saga that call
s callableSaga
, we’d have to duplicate code for extracting state data. It seems that it has to be callableSaga
’s responsibility to get its state dependencies.
So my first approach was to just pass getState
to callableSaga
:
function *daemonSaga(getState) {
// ...
yield call(callableSaga, action.payload, getState);
// ...
}
function *callableSaga(params, getState) {
// ...
}
Although it still has some drawbacks: every saga that call
s callableSaga
must accept getState
argument even if it doesn’t have dependencies on state itself; if nested call
level is longer then we have to pass getState
from the very top.
Sounds familiar, isn’t it? (Hint: react-redux).
There’s another concern about getState
argument for sagas: they become dependent on state shape which breaks encapsulation.
Proposal
- Allow sagas to be
connect
ed to the store, similar to how React components are connected by react-redux. If function decorators were supported, it could look like this:
@connectSaga(state => /* extract params */)
function* connectedSaga(getParams) {
// ...
}
Decorator returns regular saga with getState
argument. Added benefit here is that we can decouple saga from state shape by using selectors.
- Allow sagas to call connected sagas without having to pass
getState
:
function *saga() {
yield run(connectedSaga);
}
- Allow connected sagas to accept extra parameters. They can be handled in similar way as react-redux handles component props: merge them with result of selector:
@connectSaga(state => ({stateParam: ...}))
function* connectedSaga(getParams) {
const {stateParam, extraParam} = getParams();
// ...
}
function *saga() {
yield run(connectedSaga, {extraParam: ...});
}
Issue Analytics
- State:
- Created 8 years ago
- Comments:26 (25 by maintainers)
Top GitHub Comments
FYI released in 0.9.0
@aikoven What do you think of this proposition
@gaearon first proposed to provide a
yield getState()
effect so we do not pass the getState param around.@slorber proposed a more general
yield select(selector)
Effect.