-
-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Description
Use case: Most of the time, in a non-trivial application, I have to fetch data from many different sources or endpoints. The code for fetching this data is mostly the same; the only difference is the entity being fetched.
However, with idiomatic Redux, I would have to make separate actions with separate types for each entity. Though this burden is easily solved with flexible action creators, the burden now falls on the reducers: since the action.type
is a String, we can't really create "reducer creators" unless the creator dissects the action.type
string (which is a code smell).
To further illustrate, suppose we have three actions with the same shape:
{ type: 'UPDATE_FOO', data: {...} }
{ type: 'UDPATE_BAR', data: {...} }
{ type: 'UPDATE_BAZ', data: {...} }
... and each one, when sent to the respective foo, bar, baz
reducers, update the state in the exact same way for each of the foo, bar, and baz entities. To reduce code duplication, we might naïvely have a "reducer creator" that simplifies the action -> state reduction:
export default function myReducerCreator(entity) {
return (state, action) => {
let [actionType, forEntity] = action.type.split('_'); // code smell
if (actionType === 'UPDATE' && forEntity === entity) {
// do state update
return {...state, ...action.data};
}
return state;
}
}
Proposal
Assume I have a single common action type that handles state updates, with this shape: { type: 'UPDATE', entity, data }
. Then, instead of the "reducer target" being dependent on the action type, it can just be filtered via composition instead:
import { actionFilter } from 'redux';
function fooReducer(state, action) {
switch (action.type) {
case 'UPDATE':
return {...state, ...action.data};
default:
return state;
}
}
export default actionFilter((a) => a.entity === 'foo')(fooReducer);
This way, I can have a common action that can be shared in many contexts, and this provides a more scalable way of grouping actions for their respective entities.
The actionFilter
takes the signature (Function filter -> Function reducer) -> Function reducer
(or Function filter -> Function reducer -> Function reducer
when curried, as above).
I feel this would be a very useful addition to redux/utils
. What do you think?