{"action":"created","issue":{"url":"https://api.github.com/repos/rackt/redux/issues/1182","labels_url":"https://api.github.com/repos/rackt/redux/issues/1182/labels{/name}","comments_url":"https://api.github.com/repos/rackt/redux/issues/1182/comments","events_url":"https://api.github.com/repos/rackt/redux/issues/1182/events","html_url":"https://github.com/rackt/redux/issues/1182","id":123956590,"number":1182,"title":"Alternative Approach To Async Actions","user":{"login":"winstonewert","id":858493,"avatar_url":"https://avatars.githubusercontent.com/u/858493?v=3","gravatar_id":"","url":"https://api.github.com/users/winstonewert","html_url":"https://github.com/winstonewert","followers_url":"https://api.github.com/users/winstonewert/followers","following_url":"https://api.github.com/users/winstonewert/following{/other_user}","gists_url":"https://api.github.com/users/winstonewert/gists{/gist_id}","starred_url":"https://api.github.com/users/winstonewert/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/winstonewert/subscriptions","organizations_url":"https://api.github.com/users/winstonewert/orgs","repos_url":"https://api.github.com/users/winstonewert/repos","events_url":"https://api.github.com/users/winstonewert/events{/privacy}","received_events_url":"https://api.github.com/users/winstonewert/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/rackt/redux/labels/discussion","name":"discussion","color":"fbca04"},{"url":"https://api.github.com/repos/rackt/redux/labels/feedback%20wanted","name":"feedback wanted","color":"207de5"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":29,"created_at":"2015-12-27T02:06:35Z","updated_at":"2016-01-06T13:56:47Z","closed_at":null,"body":"I've been exploring an alternative to way that async actions are done in redux, and I'd appreciate any comments others might have on what I've done.\r\n\r\nTo illustrate my approach, I've changed the async example in my clone of redux: https://github.com/winstonewert/redux/tree/master/examples/async\r\n\r\nTypically, external actions are done by making the action creators asynchronous. In the case of the async example, the fetchPosts action creator dispatch a REQUEST_POSTS action to indicate the start of the request, followed by a RECEIVE_POSTS once the posts have come back from the api.\r\n\r\nIn my example, all of the action creators are synchronous. Instead, there is a function that returns the list of asynchronous actions that should currently be taking place based on the state. See my example here: https://github.com/rackt/redux/compare/master...winstonewert:master#diff-8a94dc7aa7bdc6e5390c9216a69761f8R12\r\n\r\nThe doReactions function subscribes to the store and ensures that the actual state of requests currently being made matches the state returned by the doReactions state by starting or canceling requests.\r\n\r\nSo what's the difference?\r\n\r\n1) The reactions function is a pure function of the state. This makes it easy to test.\r\n2) The actual logic of which requests to make is simpler. See the few line function in my example, versus the various pieces of logic spread through containers and action creators before.\r\n3) Makes it easy to cancel requests.\r\n\r\nAny thoughts?\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/rackt/redux/issues/comments/169329220","html_url":"https://github.com/rackt/redux/issues/1182#issuecomment-169329220","issue_url":"https://api.github.com/repos/rackt/redux/issues/1182","id":169329220,"user":{"login":"acjay","id":1256382,"avatar_url":"https://avatars.githubusercontent.com/u/1256382?v=3","gravatar_id":"","url":"https://api.github.com/users/acjay","html_url":"https://github.com/acjay","followers_url":"https://api.github.com/users/acjay/followers","following_url":"https://api.github.com/users/acjay/following{/other_user}","gists_url":"https://api.github.com/users/acjay/gists{/gist_id}","starred_url":"https://api.github.com/users/acjay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/acjay/subscriptions","organizations_url":"https://api.github.com/users/acjay/orgs","repos_url":"https://api.github.com/users/acjay/repos","events_url":"https://api.github.com/users/acjay/events{/privacy}","received_events_url":"https://api.github.com/users/acjay/received_events","type":"User","site_admin":false},"created_at":"2016-01-06T13:56:47Z","updated_at":"2016-01-06T13:56:47Z","body":"> I'm not sure what you are thinking here. I can see different drivers doing different useful things, but eliminating the control state?\r\n\r\nNah, not eliminating it, just making it an under-the-hood implementation concern, for most purposes. \r\n\r\nIt seems to me that there's really strong consensus in the Redux community that storing domain state in the store is a huge win (otherwise, why would you be using Redux at all?). Somewhat less is the consensus that storing UI state is a win, as opposed to having it be encapsulated in components. Then there's the idea of syncing browser state in the store, like the URL (redux-simple-router) or form data. But this seems to be the final frontier, of storing the status/stage of long-running process in the store.\r\n\r\nSorry if this is a tangent, but I think a highly general approach with good developer usability would have to have the following features:\r\n- Make it so the typical user doesn't really have to care about the shape of how effects are represented in the store. They should interact with simple APIs, that abstract over those details.\r\n- Make it so that effects are easily composable. It should feel natural to do things like control flow, and effects that are contingent on other effects. This, of course, is where a generator abstraction really shines. It plays nicely with most control flow, closures being a notable exception. But it's easy to see how complicated async flows are expressible in redux-saga or react-redux-controller.\r\n- Make it so that effect status can be easily surfaced to other store consumers, when desired. This would let you do things like presenting the status of a multi-effect process to the user.\r\n- Maybe this is obvious, but any subsystem that encapsulates state syncs that state with Redux, by dispatching actions.\r\n\r\nFor that second point, I think that there would have to be something pretty similar to redux-saga. It may get pretty close to what I've got in mind with its `call` wrappers. But a saga would have to be \"fast-forwardable\", in a sense, to let you deserialize it into an intermediate state.\r\n\r\nThis is all kind of a tall order, but practically speaking, I think that if there are indeed big wins to be had by having one central, serializable action record, tracking the state of an entire app at a very granular level, this would be the way to leverage it. And I think there may indeed be big wins out there. I'm imagining a much simpler way to instrument apps with user and performance analytics. I'm imagining really amazing testability, where different subsystems are coupled only through the state.\r\n \r\nI may have blown way off course now, so I'm going to leave it at that :)"}}