{"action":"created","issue":{"url":"https://api.github.com/repos/wcjohnson/redux-components/issues/4","repository_url":"https://api.github.com/repos/wcjohnson/redux-components","labels_url":"https://api.github.com/repos/wcjohnson/redux-components/issues/4/labels{/name}","comments_url":"https://api.github.com/repos/wcjohnson/redux-components/issues/4/comments","events_url":"https://api.github.com/repos/wcjohnson/redux-components/issues/4/events","html_url":"https://github.com/wcjohnson/redux-components/issues/4","id":187532891,"number":4,"title":"Dynamic \"Map\" component and reducer combinator","user":{"login":"Diggsey","id":451321,"avatar_url":"https://avatars.githubusercontent.com/u/451321?v=3","gravatar_id":"","url":"https://api.github.com/users/Diggsey","html_url":"https://github.com/Diggsey","followers_url":"https://api.github.com/users/Diggsey/followers","following_url":"https://api.github.com/users/Diggsey/following{/other_user}","gists_url":"https://api.github.com/users/Diggsey/gists{/gist_id}","starred_url":"https://api.github.com/users/Diggsey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Diggsey/subscriptions","organizations_url":"https://api.github.com/users/Diggsey/orgs","repos_url":"https://api.github.com/users/Diggsey/repos","events_url":"https://api.github.com/users/Diggsey/events{/privacy}","received_events_url":"https://api.github.com/users/Diggsey/received_events","type":"User","site_admin":false},"labels":[{"id":469619680,"url":"https://api.github.com/repos/wcjohnson/redux-components/labels/design","name":"design","color":"fef2c0","default":false},{"id":339179906,"url":"https://api.github.com/repos/wcjohnson/redux-components/labels/enhancement","name":"enhancement","color":"84b6eb","default":true}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":5,"created_at":"2016-11-06T00:21:59Z","updated_at":"2016-11-06T01:25:13Z","closed_at":null,"body":"Currently the subtree mixin allows you to have a predetermined component structure, which remains static throughout the application lifetime. This directly maps onto the redux `combineReducers` function.\r\n\r\nIt would be possible to implement a new combinator, say `combineReducersMap`, which as well as delegating actions to sub-reducers, also implements `ADD` and `REMOVE` actions itself. These actions would allow dynamically changing the set of child components and reducers.\r\n\r\nThe sequence of actions would be:\r\n- `ADD` action received, with a key and component type\r\n- Child path calculated by combining parent path with key\r\n- Component of the specified type is mounted at the child path\r\n- State at the path is initialised either from data passed with action or from a default specified by the component\r\n- Add component's reducer to the set of child reducers\r\n- Return state\r\n\r\nThis could then be encapsulated inside a `Map` component, which implements add and remove action creators.\r\n\r\nUnfortunately it would be difficult to do the same thing for a `List` type, since the way this is currently built, each component is aware of its full path, and so it would be difficult to update all of the paths. Maybe with a `componentMove` event or similar, it would be possible...\r\n\r\nThe motivation is to be able to dynamically change the layout of stores - for example, you might have allow logging into multiple accounts at the same time, like google does, in which case you can put the vast majority of your application state inside a component which gets instantiated once per logged-in account."},"comment":{"url":"https://api.github.com/repos/wcjohnson/redux-components/issues/comments/258653891","html_url":"https://github.com/wcjohnson/redux-components/issues/4#issuecomment-258653891","issue_url":"https://api.github.com/repos/wcjohnson/redux-components/issues/4","id":258653891,"user":{"login":"wcjohnson","id":10745962,"avatar_url":"https://avatars.githubusercontent.com/u/10745962?v=3","gravatar_id":"","url":"https://api.github.com/users/wcjohnson","html_url":"https://github.com/wcjohnson","followers_url":"https://api.github.com/users/wcjohnson/followers","following_url":"https://api.github.com/users/wcjohnson/following{/other_user}","gists_url":"https://api.github.com/users/wcjohnson/gists{/gist_id}","starred_url":"https://api.github.com/users/wcjohnson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wcjohnson/subscriptions","organizations_url":"https://api.github.com/users/wcjohnson/orgs","repos_url":"https://api.github.com/users/wcjohnson/repos","events_url":"https://api.github.com/users/wcjohnson/events{/privacy}","received_events_url":"https://api.github.com/users/wcjohnson/received_events","type":"User","site_admin":false},"created_at":"2016-11-06T01:25:13Z","updated_at":"2016-11-06T01:25:13Z","body":"@Diggsey \r\n\r\n>This could be a problem as it's extra state that's not part of the store.\r\n\r\nYes, I think this is the long and the short of it. And there's no way to do this *without* creating state that's not a part of the store, because fundamentally, a reducer is a function and a function can't be state.\r\n\r\nHowever, if the state that's not a part of the store is a pure function of the store, and we can guarantee it gets synced with the store, that should still be OK.\r\n\r\nSo here are my thoughts right now:\r\n\r\n- `getReducer()` is now passed the local `state` as a second argument. When first mounting, this will be the initial state. So:\r\n  ```coffeescript\r\n  getReducer: (state) => (state,action) => nextState\r\n  ``` \r\n- A new action symbol, `@@REPLACE_REDUCER`, will be added. A ReduxComponent will respond to this action by calling `getReducer()` again with its new state.\r\n- The actual reducer produced by Redux Components internally will contain an additional layer of indirection, and when it gets the `@@REPLACE_REDUCER` action, it will hot swap the reducer by calling `getReducer()`.\r\n\r\nSo, advantages:\r\n\r\n- DOES NOT require the root store to rebuild its reducer!\r\n- State, in toto, is still a pure function of Redux state. `getReducer()` is only receiving information that already is in the store.\r\n\r\nDisadvantages:\r\n\r\n- Appears to absolutely require impurity in the reducer. How do we respond to `@@REPLACE_REDUCER` purely?\r\n- Performance hit of one extra nested function call for each layer of Redux state tree depth. (Won't matter when JS finally implements proper tailcalls -- probably won't matter before that, even.)\r\n\r\nCan you see anything I don't?"}}
{"actor":{"display_login":"wcjohnson"}}