-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
how to compose redux reducers with the same actions? #897
Comments
redux-form is a great tool to use to handle forms. Reducers can pass to other reducers. The basic idea here is to create a high-order reducer that delegates down to further reducers for each group of inputs you have. Those reducers could act on generic actions such as A very striped back version of this could be:
|
I see. That nice little snippet. I'm going to use that. I'm still just a little confused though. One of the things I like to consider when building a web application is if I can have two versions of app running side by side in different divs. So long as there isnt user auth and browser cookies that are inherently global, then a well-written application (without globals) should be able to do this. The problem I'm having with Redux when approaching this problem is suppose I build a todo's app. The entire todo's app is done. Ok, now I want to have two todos apps side-by-side. It should be really easy, right? Well it seems I'll have to change all of my reducers to be aware of the fact that there are multiple todos apps. Ideally, there would be some way of contextualizing each todo's app so they wouldnt have to be aware of where they are in the grand scheme of things. |
Ideally you could do something like this: App = React.createClass({
render: function() {
return (
<div>
<TodosApp id=1/>
<TodosApp id=2/>
</div>
)
}
}) And the id in there basically "lifts" all the actions, reducers, and state to reflect that... |
I guess what I'm thinking is you'd have a store paired with each component. In this case, you'd have store for each TodosApp. Then hopefully theres some way of combining stores... but I'm not sure thats possible... |
You could that. There's only ever one store in redux, just compose your app's main reducer in a higher reducer.
Then bind the id prop from |
Hmm. I was under the impression that the actions should only be discriminated only by the "type" property. At least thats what it seems like. The Redux dev tool looks for the type, right? What if the type was an array and the reducer was concerned only with the head of the type array. That way, it would be easier to abstract. Here's a solid example -- I'm very curious what you think... We have a simple input action/reducer pair that concerns itself with a single input. inputReducer = function(state='', action) {
if (action.type[0] === 'ON_CHANGE') {
return action.value
}
return state
}
inputOnChangeAction = function(e) {
return {
type: ['ON_CHANGE'],
value: e.target.value
}
} The goal is to reuse those actions and reducers to abstract up to a form component like this: Form = React.createClass({
render: function() {
return (
<input value={this.props.username} onChange={this.props.usernameOnChange}/>
<input value={this.props.password} onChange={this.props.passwordOnChange}/>
)
}
}) So what if we has these high-order functions to lift the actions and reducers by adding a new type to the beginning of the type array. liftAction = function(type, f) {
return function(arg) {
let action = f(arg)
action.type = [type, ...action.type]
return action
}
}
liftReducer = function(type, f) {
return function(state, action) {
if (action.type[0] === type) {
return f(state, action.splice(1))
} else {
return state
}
}
} This the top-level actions and reducers work like this: reducer = function(state={username:'', password:''}, action) {
return {
username: liftReducer('username', inputReducer)
password: liftReducer('password', inputReducer)
}
}
actions = {
usernameOnChange: liftAction('username', inputOnChangeAction)
passwordOnChange: liftAction('password', inputOnChangeAction)
} Does that make sense? Thus for the side-by-side todo's example, we'd basically just do this: reducer = function(state, action) {
return {
todos1: liftReducer('todos1', todosReducer)
todos2: liftReducer('todos1', todosReducer)
}
}
// liftActions just maps liftAction over the object values...
todos1actions = liftActions('todos1', todosActions)
todos2actions = liftActions('todos2', todosActions) Does that make sense? Is this formalized in any way? |
Almost, though instead of adding anything to the type, you can just add it to the action itself. Again, refering to Therefor, you wouldn't need to a That being said, what's great about Redux is that it is as un-opinionated as it gets, which means if there is a viable alternative, by all means go for it, I'm just pointing out how these problems have already been solved for reference. |
I think this is pretty much the same as #822. |
Relevant new discussion: #1528 |
```javascript function firstName(state = '', action = {}) { if (action.type === SET_FIRST_NAME) { return action.payload } return state } function lastName(state = '', action = {}) { if (action.type === SET_LAST_NAME) { return action.payload } return state } const reducer = combineReducers({ firstName, lastName }) function handleSetFullName(state, action) { if (action.type === SET_FULL_NAME) { const parts = action.payload.split(' ') return { ...state, firstName: parts[0], lastName: parts[1] } } return state } export default composeReducers( reducer, handleSetFullName ); ``` reduxjs#897
``` function firstName(state = '', action = {}) { if (action.type === SET_FIRST_NAME) { return action.payload } return state } function lastName(state = '', action = {}) { if (action.type === SET_LAST_NAME) { return action.payload } return state } const reducer = combineReducers({ firstName, lastName }) function handleSetFullName(state, action) { if (action.type === SET_FULL_NAME) { const parts = action.payload.split(' ') return { ...state, firstName: parts[0], lastName: parts[1] } } return state } export default composeReducers( reducer, handleSetFullName ); ``` reduxjs#897
its been a while, but I just had an idea and put together a little demo: https://github.com/ccorcos/reduxish Its basically adopting a the elm 0.16 architecture to redux. |
I'm just getting started with redux and it looks amazing, but I'm a little worried about abstraction.
Suppose I have a really simple input component
Now its trivial to hook this up to a component with an input.
But what happens when I have more than one input?
Ok, I suppose we could change the action type to specify which input its referring too.
But now suppose I place two of the same views side-by-side? Now I need to modify the action yet again to specify which input in which view I'm referring to.
Oy vey. Whats tough about this is that the input reducer somehow needs to know about how the rest of the app is structured. That just doesnt seem right. Ideally we would be able to abstract out the input's actions and reducers based on how the parent decides to arrange them. I suppose we could do this with a high-order function. But this is all getting pretty tedious. Am i missing something? How are you dealing with this?
The text was updated successfully, but these errors were encountered: