Skip to content
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

Multiple reducers consuming one action #34

Open
skeet70 opened this issue Jul 9, 2019 · 5 comments
Open

Multiple reducers consuming one action #34

skeet70 opened this issue Jul 9, 2019 · 5 comments

Comments

@skeet70
Copy link

skeet70 commented Jul 9, 2019

It's a semi-common pattern to have a single action created by an async action (like LOAD_USER or UPDATE_FOO) that multiple reducers listen to and pull state from. It seems like this isn't possible to me with immer-reducer. Is this possible, or is there a low boilerplate alternative?

@esamattis
Copy link
Owner

I've never had a use case for this. Can you provide an example?

This actually explicitly forbidden in immer-reducer now:

https://github.com/epeli/immer-reducer/blob/1c757d5ac57f51c2ecb7775d6498813156872256/src/immer-reducer.ts#L193-L197

Eg. if the assertion would be removed following would be possible:

class Foo1 extends ImmerReducer<State> {
  customName = "bar"
  setFoo(name: string) {
    this.draftState.foo1 = name;
  }
}

class Foo2 extends ImmerReducer<State> {
  customName = "bar"
  setFoo(name: string) {
    this.draftState.foo2 = name;
  }
}

By default immer-reducer generates the action types from the class name & method name but with the customName property it is possible to override the class name. If it is same between multiple classes their methods will receive the same action no matter which method is used to dispatch the action.

But there's reason why this is forbidden: The setFoos between the classes has no relation with each other. They can have completely different type signatures and it would be up to the user to make sure they are the same. Which is against the design goal of immer-reducer to be as type-safe as possible.

@esamattis
Copy link
Owner

As a workaround I would recommend just dispatching different actions from your async action:

dispatch(Actions.setLoadedUserForBar(user));
dispatch(Actions.setLoadedUserForFoo(user));

react-redux now days even exports the batch helper which avoids extra renders when used:

batch(() => {
  dispatch(Actions.setLoadedUserForBar(user));
  dispatch(Actions.setLoadedUserForFoo(user));
});

Also if the actions/reducers are in the same class you can alternatively define a combining action/reducer:

setLoaderUser(user: user) {
  this.setLoadedUserForBar(user);
  this.setLoadedUserForFoo(user);
}

@skeet70
Copy link
Author

skeet70 commented Jul 10, 2019

An easy example (mentioned by redux starter kit) is a USER_LOGGED_OUT action that many reducers across the application may need to change their slice of state in response to.

That project seems to have similar goals and the way they handle it is by having an extraReducers option when creating a slice (which is similar in structure to your Reducer class). You use extraReducers to provide references to imported actions from other places that this reducer should listen to. This introduces its own edge cases to watch out for that they call out, but it does solve the general issue in a pretty type safe way.

@esamattis
Copy link
Owner

I see.

I'd really like to solve this with decorators too:

@action("LOAD_USER")
setUserLoggedIn(user: User) {
 // ...
}

Where the @action() decorator would force the action type to be what ever you want and you could share action types using it. This does not solve the typing issue (I don't think its solvable to beging with).

@zdila
Copy link

zdila commented Dec 9, 2019

I would also appreciate to have this feature. I use it often in the projects I work on. One is for example https://github.com/FreemapSlovakia/freemap-v3-react and such an action there is for example clearMap. I am trying to rewrite it to use immer-reducer as I started to have a need to access state "from a different branch" in a reducer and immer-reducer composeReducers makes it easy.

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

3 participants