-
-
Notifications
You must be signed in to change notification settings - Fork 15.2k
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
Proposal: declarative reducers #1024
Comments
As far as I can say, similar syntax has been proposed multiple times, and even mentioned in the docs. Generally speaking, reducer does not have to map But nothing stops you from using this syntax in your reducers, especially given the fact how less code this requires you to implement. |
From http://redux.js.org/docs/recipes/ReducingBoilerplate.html#generating-reducers:
|
gaearon, does "redux" package provide "createReducer" function? Or it need to be copy-pasted every time? |
Reducer composition is a common pattern in Redux. See function products(state, action) {
switch (action.type) {
case ADD_TO_CART:
return {
...state,
inventory: state.inventory - 1
}
default:
return state
}
}
function byId(state = {}, action) {
switch (action.type) {
case RECEIVE_PRODUCTS:
return {
...state,
...action.products.reduce((obj, product) => {
obj[product.id] = product
return obj
}, {})
}
default: // <------------- how do you express this with a function map?
const { productId } = action // <------------- predicate by action field, not by action type!
if (productId) {
return {
...state,
[productId]: products(state[productId], action) // <------------- or this call?
}
}
return state
}
}
function visibleIds(state = [], action) {
switch (action.type) {
case RECEIVE_PRODUCTS:
return action.products.map(product => product.id)
default:
return state
}
}
export default combineReducers({
byId,
visibleIds
}) // <------------- or how do you combine reducers if they're objects? If we force users to declare reducers as object maps, many powerful patterns that are possible with functions become harder and non-obvious. This is why we don't encourage users to take shortcuts. If you discover a shortcut and find it convenient, use it, but we don't want to limit your imagination because otherwise you won't come up with reducer composition-based solutions like the code above. |
It doesn't. But |
May you give an example of such pattern? |
I added comments to the example. |
Same discussion in the past: #883. |
Few general questions:
|
There's just one core project—Redux itself. Yes, it's lower level. It's opinionated where it really matters (e.g. plain object actions, pure reducers), but other than that, you're free to implement your own conventions.
I wouldn't expect to find bugs in Redux itself because it's very small and has been thoroughly tested (we barely change the code these days). Generally it's a good idea to watch out for open https://github.com/rackt/redux/issues and offer help there if you think you can spare some. |
Have a look at awesome-redux and the Ecosystem page in the docs. |
Isn't this what https://github.com/acdlite/redux-actions does anyway? I don't think it's the switch statement in itself but rather the semantics of it in js that makes it unappealing (and probably the need to import the constant too) |
Constants are just strings. Those who don't like constants are free to use strings directly.. |
@dzannotti redux-actions is for action creators, not for reducers 😉 |
using string directly leads to inconsistency way too easely |
And that's why we propose to use constants 😉
|
@omnidan no it's for both const reducer = handleActions({
INCREMENT: (state, action) => ({
counter: state.counter + action.payload
}),
DECREMENT: (state, action) => ({
counter: state.counter - action.payload
})
}, { counter: 0 }); |
Ah I see 😄 Well, TIL. |
@dzannotti Constants vs strings vs middleware, in the end it's really just a question of preference. :) |
@SebastienDaniel yep that's what i'm doing currently actually :) |
One side effects of using constants and importing them in reducers, is they document which actions the reducers use. In simple apps, this may not matter much. But for complex apps, more than one, mostly unrelated reducers may need to change the state based on an action. |
I propose provide option for defining reducer with a plain JS object where keys are action types and functions defined with ES6 arrow functions (which leads to less code):
Here code example based on of Redux TodoMVC reducer.
How it declared now:
How I propose to declare:
Pros
And here function to convert declarative reducer to standard reducer:
The text was updated successfully, but these errors were encountered: