{"action":"created","issue":{"url":"https://api.github.com/repos/gaearon/redux/issues/307","labels_url":"https://api.github.com/repos/gaearon/redux/issues/307/labels{/name}","comments_url":"https://api.github.com/repos/gaearon/redux/issues/307/comments","events_url":"https://api.github.com/repos/gaearon/redux/issues/307/events","html_url":"https://github.com/gaearon/redux/issues/307","id":96829459,"number":307,"title":"async reducer workflow","user":{"login":"jquense","id":339286,"avatar_url":"https://avatars.githubusercontent.com/u/339286?v=3","gravatar_id":"","url":"https://api.github.com/users/jquense","html_url":"https://github.com/jquense","followers_url":"https://api.github.com/users/jquense/followers","following_url":"https://api.github.com/users/jquense/following{/other_user}","gists_url":"https://api.github.com/users/jquense/gists{/gist_id}","starred_url":"https://api.github.com/users/jquense/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jquense/subscriptions","organizations_url":"https://api.github.com/users/jquense/orgs","repos_url":"https://api.github.com/users/jquense/repos","events_url":"https://api.github.com/users/jquense/events{/privacy}","received_events_url":"https://api.github.com/users/jquense/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/gaearon/redux/labels/discussion","name":"discussion","color":"fbca04"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":31,"created_at":"2015-07-23T14:37:54Z","updated_at":"2015-08-08T22:42:12Z","closed_at":null,"body":"Right now the composition of stores is strictly a sync composition of functions that return state, and any async stuff needs to be put in an actionCreator (with some sort of async middleware like thunk).\r\n\r\nGenerally this works out nicely, is straightforward and Easy To Reason About™ and all around a pleasant API to work with. I want to say up front that the suggestion here is not due to an inability to get something done in Redux, but a philosophical one about concerns and the their proper place in the flux cycle. I know I _can_ accomplish the following in action creators, my contention is that it not the _right_ place to do it, but the api forces it.\r\n\r\nMy issue is that I have a few use cases where the \"reducing\" work of moving one state to a new one is just asynchronous.\r\n\r\n1. __heavy computation/webworkers__: Needing reduce a large array doing a bunch of hefty calculations, that needs to be split over a few event loop ticks. Not super common, but it happens often enough in our apps. some real examples: doing a bunch of fuzzy text matching against 15000 contact names. Big D3 graph stuff.\r\n\r\n2. __model validation/parsing__: this is more controversial but the following example is common to us. I am not talking about the fetching of items from the server, but about taking an item out of state, putting it in a form, and then updating that item later. These items may or may not be saved to the server.\r\n\r\n  ```js\r\n  schema.validateAndCast(formValue)\r\n    .then( castValue => state.collection.push(castValue))\r\n    .catch( err => state.errors.push(err))\r\n  ```\r\n\r\n  In general I think validation stuff is going to be sitting your action creators as long as you are doing to server syncing there (and I think you should). Often, in addition to that we have wanted helpers we use to update state in reducers to be able to validate and parse the objects they are passed in, since this is part of the reducing process.\r\n\r\nto the broader point, there is no reason that \"reducing\" as an action _must_ or _should_ be synchronous. It can be frustrating to have to split \"business\" logic for managing state into a bunch of places, when there is a really good place for it already!\r\n\r\nOn redux's side most of this could be addressed by providing a single hook somewhere around here: https://github.com/gaearon/redux/blob/breaking-changes-1.0/src/createStore.js#L96. If there was some sort of callback hook to set currentState then anyone could create their own async combineReducers however they wish."},"comment":{"url":"https://api.github.com/repos/gaearon/redux/issues/comments/129059342","html_url":"https://github.com/gaearon/redux/issues/307#issuecomment-129059342","issue_url":"https://api.github.com/repos/gaearon/redux/issues/307","id":129059342,"user":{"login":"danmaz74","id":302674,"avatar_url":"https://avatars.githubusercontent.com/u/302674?v=3","gravatar_id":"","url":"https://api.github.com/users/danmaz74","html_url":"https://github.com/danmaz74","followers_url":"https://api.github.com/users/danmaz74/followers","following_url":"https://api.github.com/users/danmaz74/following{/other_user}","gists_url":"https://api.github.com/users/danmaz74/gists{/gist_id}","starred_url":"https://api.github.com/users/danmaz74/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danmaz74/subscriptions","organizations_url":"https://api.github.com/users/danmaz74/orgs","repos_url":"https://api.github.com/users/danmaz74/repos","events_url":"https://api.github.com/users/danmaz74/events{/privacy}","received_events_url":"https://api.github.com/users/danmaz74/received_events","type":"User","site_admin":false},"created_at":"2015-08-08T22:42:12Z","updated_at":"2015-08-08T22:42:12Z","body":"I'll add my two cents here, as someone who is still considering if we should switch from \"vanilla Flux\" to Redux. I don't like the name ActionCreator a lot, but adopting a terminology that conflicted with Facebook's examples (ie, call the ActionCreator an Action) would make it really difficult for someone coming from there to understand and adopt Redux.\r\n\r\nSecond, regarding the replayability, that is extremely useful for debugging, and also for automated testing. But the replayability will only work for a sequence of dispatched Actions, not ActionCreator calls - Actions (in the original sense) have deterministic effects, while ActionCreator calls don't, exactly because they can include non-deterministic async calls.\r\n\r\nKeeping the deterministic code separated from the non-deterministic one has a very big advantage: it makes testing the deterministic actions very easy. To account for the non-deterministic async part of the code, you \"simply\" need to test the different sequences of actions and the different results that can come from the async calls: test what happens if AsyncCall1 finishes before AsyncCall2, test what happens if AsyncCall1 returns a timeout error, etc. \r\n\r\nBeing able to do that is one of the most important things that makes me inclined to seriously consider Redux to solve some of the problems we were finding with vanilla Flux."}}