{"action":"created","issue":{"url":"https://api.github.com/repos/gaearon/redux/issues/277","labels_url":"https://api.github.com/repos/gaearon/redux/issues/277/labels{/name}","comments_url":"https://api.github.com/repos/gaearon/redux/issues/277/comments","events_url":"https://api.github.com/repos/gaearon/redux/issues/277/events","html_url":"https://github.com/gaearon/redux/issues/277","id":95303570,"number":277,"title":"How to implement an extensible app using Redux?","user":{"login":"anatoliyarkhipov","id":1934180,"avatar_url":"https://avatars.githubusercontent.com/u/1934180?v=3","gravatar_id":"","url":"https://api.github.com/users/anatoliyarkhipov","html_url":"https://github.com/anatoliyarkhipov","followers_url":"https://api.github.com/users/anatoliyarkhipov/followers","following_url":"https://api.github.com/users/anatoliyarkhipov/following{/other_user}","gists_url":"https://api.github.com/users/anatoliyarkhipov/gists{/gist_id}","starred_url":"https://api.github.com/users/anatoliyarkhipov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/anatoliyarkhipov/subscriptions","organizations_url":"https://api.github.com/users/anatoliyarkhipov/orgs","repos_url":"https://api.github.com/users/anatoliyarkhipov/repos","events_url":"https://api.github.com/users/anatoliyarkhipov/events{/privacy}","received_events_url":"https://api.github.com/users/anatoliyarkhipov/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-07-15T22:24:43Z","updated_at":"2015-07-17T12:15:14Z","closed_at":null,"body":"Maybe this question generally about Flux, not Redux, but I would like to see an example on Redux.\r\n\r\nBy \"extensible\" I mean something like the next example:\r\n\r\nImagine that we have some basic app which displays a grid with data. Click on a row in this grid runs the \"select\" action. And reducer, which responsible to process this action, marks the clicked row as selected (and the grid component adds some class to the row, e.g. `selected`).\r\n\r\nAnd now we want to implement some module. It's a viewer, which will be displayed at the right side of the grid. And this viewer will display the selected record. But we must to load details of the record, because viewer needs some additional data which not displayed in the grid.\r\n\r\nThe question: at what moment and where should I load details of the record? Without changing the original app code. In other words: how to make the original app code extensible for this purpose?\r\n\r\nI have three possible solutions, but I feel like that there is something wrong with all of this:\r\n\r\n* Events. E.g. the \"select\" action fires the `selectionChange` event, and any modules can listen for it and run its own actions like `fetchDetails`. \r\n\r\n```\r\nregisterHandler('selectionChanged', (data) => {\r\n    \r\n    ModuleActions.fetchDetails(data.id)\r\n})\r\n```\r\n\r\n* A registry. We can implement some registry of actions, and decorate the original `select` action with a custom action, which will run the `fetchDetails` after the original select:\r\n\r\n```\r\n// Somewhere in the app initialization code\r\n\r\nregistry.add('select`, () => /* Some original action */ }\r\n\r\n// Somewhere in the module initialization code\r\n\r\nregistry.decorate('select', original => {\r\n\r\n    return (data) => (dispatch) => {\r\n        \r\n        // Call the original select action\r\n        original(data)\r\n        \r\n        // The custom behavior\r\n        ModuleActions.fetchDetails(data.id)\r\n    }    \r\n})\r\n```\r\n\r\n* Some \"Smart\" viewer component watches for the selected record in the app state and run the `fetchDetails` action when it's changed.\r\n\r\n```\r\n// ...\r\ncomponentWillReceiveProps({ selected }) {\r\n    \r\n    if (selected != this.state.selected) {\r\n\r\n        this.setState({ selected })\r\n\r\n        ModuleActions.fetchDetails(selected.id)\r\n    }\r\n}\r\n```\r\n\r\nWhat you think about that?\r\n\r\n\r\n"},"comment":{"url":"https://api.github.com/repos/gaearon/redux/issues/comments/122258328","html_url":"https://github.com/gaearon/redux/issues/277#issuecomment-122258328","issue_url":"https://api.github.com/repos/gaearon/redux/issues/277","id":122258328,"user":{"login":"gaearon","id":810438,"avatar_url":"https://avatars.githubusercontent.com/u/810438?v=3","gravatar_id":"","url":"https://api.github.com/users/gaearon","html_url":"https://github.com/gaearon","followers_url":"https://api.github.com/users/gaearon/followers","following_url":"https://api.github.com/users/gaearon/following{/other_user}","gists_url":"https://api.github.com/users/gaearon/gists{/gist_id}","starred_url":"https://api.github.com/users/gaearon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gaearon/subscriptions","organizations_url":"https://api.github.com/users/gaearon/orgs","repos_url":"https://api.github.com/users/gaearon/repos","events_url":"https://api.github.com/users/gaearon/events{/privacy}","received_events_url":"https://api.github.com/users/gaearon/received_events","type":"User","site_admin":false},"created_at":"2015-07-17T12:15:14Z","updated_at":"2015-07-17T12:15:14Z","body":"Can you just open new issues? It's easier to discuss & search them later if each issue is focused around a single specific problem or question."}}