Skip to content

Proposal: action filter utility #912

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

Closed
davidkpiano opened this issue Oct 18, 2015 · 5 comments
Closed

Proposal: action filter utility #912

davidkpiano opened this issue Oct 18, 2015 · 5 comments

Comments

@davidkpiano
Copy link
Contributor

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?

@omnidan
Copy link
Contributor

omnidan commented Oct 18, 2015

Just like #658, this would probably be better as an external reducer enhancer. I was actually thinking about writing a small library like redux-undo for this use case.

@davidkpiano
Copy link
Contributor Author

@omnidan This is what I had in mind: https://github.com/davidkpiano/estado/blob/master/src/utils/signal-filter.js (library-agnostic code, which is why it's called signalFilter instead of actionFilter, but same thing).

@omnidan
Copy link
Contributor

omnidan commented Oct 18, 2015

@davidkpiano looks good 👌

It probably doesn't make sense to have it as part of the redux core, though.
I'll leave this decision to @gaearon 😛

@omnidan
Copy link
Contributor

omnidan commented Oct 18, 2015

@davidkpiano you can use this as a template if you want: https://github.com/omnidan/redux-ignore - it's a little bit simpler (takes an array instead of a function). Maybe you could even send me a PR so it accepts both, arrrays and functions.

@omnidan
Copy link
Contributor

omnidan commented Oct 18, 2015

This is part of redux-ignore now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants