{"action":"created","issue":{"url":"https://api.github.com/repos/yelouafi/redux-saga/issues/43","labels_url":"https://api.github.com/repos/yelouafi/redux-saga/issues/43/labels{/name}","comments_url":"https://api.github.com/repos/yelouafi/redux-saga/issues/43/comments","events_url":"https://api.github.com/repos/yelouafi/redux-saga/issues/43/events","html_url":"https://github.com/yelouafi/redux-saga/issues/43","id":127639188,"number":43,"title":"Proposal: Parametric sagas","user":{"login":"aikoven","id":857709,"avatar_url":"https://avatars.githubusercontent.com/u/857709?v=3","gravatar_id":"","url":"https://api.github.com/users/aikoven","html_url":"https://github.com/aikoven","followers_url":"https://api.github.com/users/aikoven/followers","following_url":"https://api.github.com/users/aikoven/following{/other_user}","gists_url":"https://api.github.com/users/aikoven/gists{/gist_id}","starred_url":"https://api.github.com/users/aikoven/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aikoven/subscriptions","organizations_url":"https://api.github.com/users/aikoven/orgs","repos_url":"https://api.github.com/users/aikoven/repos","events_url":"https://api.github.com/users/aikoven/events{/privacy}","received_events_url":"https://api.github.com/users/aikoven/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2016-01-20T09:25:52Z","updated_at":"2016-01-21T09:26:40Z","closed_at":null,"body":"I've run into following problem:\r\nSuppose we have two sagas: one daemon, and one `call`able:\r\n```js\r\nfunction *daemonSaga() {\r\n  while (true) {\r\n    const action = take(...);\r\n\r\n    yield call(callableSaga, action.payload);\r\n  }\r\n}\r\n\r\nfunction *callableSaga(params) {\r\n  // ...\r\n}\r\n```\r\n\r\nNow, 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.\r\n\r\nSo my first approach was to just pass `getState` to `callableSaga`:\r\n```js\r\nfunction *daemonSaga(getState) {\r\n  // ...\r\n    yield call(callableSaga, action.payload, getState);\r\n  // ...\r\n}\r\n\r\nfunction *callableSaga(params, getState) {\r\n  // ...\r\n}\r\n```\r\n\r\nAlthough 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.\r\n\r\nSounds familiar, isn't it? (Hint: [react-redux](https://github.com/rackt/react-redux)).\r\n\r\nThere's another concern about  `getState` argument for sagas: they become dependent on state shape which breaks encapsulation.\r\n\r\n## Proposal\r\n* Allow sagas to be `connect`ed to the store, similar to how React components are connected by react-redux. If [function decorators](https://github.com/wycats/javascript-decorators/issues/4) were supported, it could look like this:\r\n```js\r\n@connectSaga(state => /* extract params */)\r\nfunction* connectedSaga(getParams) {\r\n  // ...\r\n}\r\n```\r\nDecorator returns regular saga with `getState` argument. Added benefit here is that we can decouple saga from state shape by using selectors.\r\n* Allow sagas to call connected sagas without having to pass `getState`:\r\n```js\r\nfunction *saga() {\r\n  yield run(connectedSaga);\r\n}\r\n```\r\n* 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:\r\n```js\r\n@connectSaga(state => ({stateParam: ...}))\r\nfunction* connectedSaga(getParams) {\r\n  const {stateParam, extraParam} = getParams();\r\n  // ...\r\n}\r\n\r\nfunction *saga() {\r\n  yield run(connectedSaga, {extraParam: ...});\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/yelouafi/redux-saga/issues/comments/173512993","html_url":"https://github.com/yelouafi/redux-saga/issues/43#issuecomment-173512993","issue_url":"https://api.github.com/repos/yelouafi/redux-saga/issues/43","id":173512993,"user":{"login":"yelouafi","id":5453835,"avatar_url":"https://avatars.githubusercontent.com/u/5453835?v=3","gravatar_id":"","url":"https://api.github.com/users/yelouafi","html_url":"https://github.com/yelouafi","followers_url":"https://api.github.com/users/yelouafi/followers","following_url":"https://api.github.com/users/yelouafi/following{/other_user}","gists_url":"https://api.github.com/users/yelouafi/gists{/gist_id}","starred_url":"https://api.github.com/users/yelouafi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yelouafi/subscriptions","organizations_url":"https://api.github.com/users/yelouafi/orgs","repos_url":"https://api.github.com/users/yelouafi/repos","events_url":"https://api.github.com/users/yelouafi/events{/privacy}","received_events_url":"https://api.github.com/users/yelouafi/received_events","type":"User","site_admin":false},"created_at":"2016-01-21T09:26:40Z","updated_at":"2016-01-21T09:26:40Z","body":"@aikoven Can't you pass the required data (entities & locale setting) in the action payload ? Then the only dependency you'll have to the 2 selectors will be in the component firing the action."}}