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

Question on how to manage dependency between reducers #1518

Closed
stuartkeith opened this issue Mar 13, 2016 · 9 comments
Closed

Question on how to manage dependency between reducers #1518

stuartkeith opened this issue Mar 13, 2016 · 9 comments

Comments

@stuartkeith
Copy link

I'm writing my first redux application and have run into an issue.

Say I have a basic todo application - a reducer provides an array of todos. The view is a series of tabs with each todo's header on it. You can select a tab and that todo's edit view will appear below.

My first approach was to create another reducer that tracks the selected tab's ID (as "selected todo" in this case is UI state, I don't want to put it in the todo reducer's state). The reducer receives a "SELECT_TODO" action with the ID attached and updates accordingly. Then the view can render the tabs and the selected todo's edit view below. Pretty straightforward. A new todo could be selected automatically by the reducer listening for an ADD_TODO action and returning its ID.

What I'm stuck on is how to handle the user deleting the selected todo and having a new selected todo calculated automatically - I can have the "selected todo" reducer listen to a REMOVE_TODO action,
but in order to calculate a new value it needs access to the list of todos - it will try to select the next todo,
or the previous if the selected todo is at the end of the list.

Any suggestions on how to best structure things in this scenario? Since I'm new to redux it would be really helpful to get some advice - I have a few ideas that would technically work but I'm not sure if I'm on the right track or not.

Thanks.

@johanneslumpe
Copy link
Contributor

I would handle this in an action creator using redux-thunk. You will have access to the whole state in your action creator. This allows you to either

a) fire two actions, one for removing one for setting the new selected id
b) fire a single action for removing with a new selected in in the payload.

In both cases you can randomly select a new item from your state in the action creator.

@stuartkeith
Copy link
Author

Thanks @johanneslumpe. I haven't been using redux-thunk, but when I read your answer mention using two actions I realised my real issue may actually be in the action creator stage - my actions are not passing all of the data the reducers require.

I can pass the existing list of todos to my add/remove todo action creators - it makes sense to me that a reducer would need to know where this data will ultimately be removed from or added to in order to calculate its result.

It does mean every add/remove todo view requires the current list of todos, but at least it's explicit where the data came from.

@gaearon
Copy link
Contributor

gaearon commented Mar 13, 2016

I can pass the existing list of todos to my add/remove todo action creators - it makes sense to me that a reducer would need to know where this data will ultimately be removed from or added to in order to calculate its result.

It’s best if you avoid passing large pieces of state as part of the actions. This creates a sort of “feedback loop” where it’s hard to trace where the data is coming from in case there is a mistake.

@gaearon
Copy link
Contributor

gaearon commented Mar 13, 2016

I think that REMOVE_TODO including nextSelectedId is a good compromise. You let the view calculate it, and the view knows which one should be selected. For example, the view might apply some sorting or filtering to the results, so in this case in particular the view knows which one is to be selected better than the reducers can.

@gaearon gaearon closed this as completed Mar 13, 2016
@stuartkeith
Copy link
Author

Thank you @gaearon, that makes perfect sense.

@ELIYAHUT123
Copy link

I have a problem with a diferent kind of dependency:

I'm creating a hamburgers delivery shop.
In the shop I have ingredients and meals (meal consist of ingredients).
Every ingredient has a unique id.
A meal instance contains a list of ingredients ids (the ingredients it contains).
Therefore - I want to load the ingredients details before I load the meals (so I don't have problems when I try to display the meals at the menu page).
I need a way to fire LOAD_MEALS only after the ingredients reducer is done.
(dispatching LOAD_INGREDIENTS before dispatching LOAD_MEALS doesn't solve the problem because loading the ingredients might take longer than loading the meals).

How can I solve this problem?

@markerikson
Copy link
Contributor

@ELIYAHUT123 : That's a usage question, and should really be asked on Stack Overflow instead of this issues tracker.

That said, it sounds like you may be a bit confused. The reducer function call is 100% synchronous, so saying "the ingredients reducer is done" doesn't make sense. I think what you mean is "after the ingredients have been loaded from the server".

But yeah, ask that on SO - you'll get more attention and a better response than here.

@ELIYAHUT123
Copy link

ELIYAHUT123 commented Sep 7, 2016

@markerikson: Maybe I wasn't clear enought.
I'll explain:
For reasons of efficiency I fetch all the data (the ingredients and the meals) together from the server.
If I were to dispatch FETCH_ALL_DATA and let both the ingredients and the meals redcers "listen" to this action (and update the store asynchronously) - I would run into problems when trying to display a meal that its ingredients are not loaded to the store yet (that's what I ment when I wrote "the ingredients reducer is done" - done loading the fetched ingredients to the store).
I will try SO as well, I just saw the title of this issue and thought my question is suitable.

@ELIYAHUT123
Copy link

ELIYAHUT123 commented Sep 7, 2016

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

No branches or pull requests

5 participants