I'm using redux for my react-native project. I have to use some Switch components(true or false) to select differents colors and save them into an array in the state. I can have an empty array or for example ["black","white"] according with my Switchs selection.
My question is if is better to have one action named "EDIT_COLOR" and inside it an "IF" statement to check if I'm adding or removing the color from the array, or have two actions one for adding and another one for removing.
Number one has the advantage of pass just one action to the components but the reducer get a little bigger with the IF statement inside.
Thanks a lot for your comments!
As long as actions are manageable, create one reducer. However, if the actions functionalities are not related, then you should create separate reducers for each one. For instance, creating different reducers for user authentication and fetching data from an API.
Related
Each big components get its own list of actions. Separation of files implies that they are isolate actions. But from my understanding if a type of an action matches the type of another action in completely separate file meant for different reducer will still cause problem.
EDIT:
if i have two sections in the app. One has reducer for action SET_SCROLL, and other section has that too. If i update scroll position in section 2, by firing SET_SCROLL. This would cause section 1's state to change. Now imagine 100s of actions, how do you prevent naming conflicts? I understand in redux you can't associate set of actions with a certain reducers.
Yes, this is why you should be careful when defining action types. The "Reusing Reducer Logic" docs page gives examples of how this can be a problem when you want to reuse a given reducer in more than one place, and shows some ways around that.
We specifically recommend defining action types as "domain/someAction" to help avoid clashes.
Note that it's also possible (and recommended) to have many different parts of the reducer logic all independently respond to the same dispatched action
I have watched a few videos about reducers, and they all claimed that I should use only one reducer and state for my whole project and I should combine every reducer into one big reducer.
Now my question is, why would I do this? Imagine I have a big application and I combine all reducers. My combined reducer would be huge and a single state change would take quite long since we need to check every single reducer slice.
Should I really just use one reducer for a bigger project? Why should we combine them, instead of creating multiple stores, and what about the performance?
As your app grows more complex, you'll want to split your reducing
function into separate functions, each managing independent parts of
the state.
.combineReducers(...)
Thanks a lot.
Per the Redux FAQ entry on the performance of "calling all reducers":
It's important to note that a Redux store really only has a single reducer function. The store passes the current state and dispatched action to that one reducer function, and lets the reducer handle things appropriately.
Trying to handle every possible action in a single function does not scale well, simply in terms of function size and readability, so it makes sense to split the actual work into separate functions that can be called by the top-level reducer.
However, even if you happen to have many different reducer functions composed together, and even with deeply nested state, reducer speed is unlikely to be a problem. JavaScript engines are capable of running a very large number of function calls per second, and most of your reducers are probably just using a switch statement and returning the existing state by default in response to most actions.
Also, from the FAQ entry on whether you should create multiple stores:
It is possible to create multiple distinct Redux stores in a page, but the intended pattern is to have only a single store. Having a single store enables using the Redux DevTools, makes persisting and rehydrating data simpler, and simplifies the subscription logic.
However, creating new stores shouldn't be your first instinct, especially if you come from a Flux background. Try reducer composition first, and only use multiple stores if it doesn't solve your problem.
I am using same filter two time same screen for different purpose. Now updating at one place automatically updates the dependent values on second filter as well.
You are going to need two states in your Redux store - one for each filter. Then you need to connect one state to one filter, and the other state to the other filter.
You don't need to duplicate your reducers and actions though. Your action could take an filterId as input, and then pass this down to the reducer. The reducer updates different states based on which filterId is passed in from the action.
Hope that makes sense! Feel free to add follow up questions or additional information about your problem to get a more detailed explanation!
I have a react native app that uses many screens to manage the data in a large object.
For example, each of the following is a screen to manage a portion of 1 object in this app: address, contacts, images, notes, and a few more.
Is there any issue that would conflict with best practices or performance to use a single reducer which passes back the entire object in state?
or should my reduces and state be more screen oriented, passing back only the properties of the object that each screen is handling?
Straight forward answer. It depends
Depends on the data stored by each reducer.(state maintained by each)
If it's complex data better to create a separate reducer.
If each screen's state is just a flat JSON object, keep all of them in single reducer.
At the end combineReducers() will make them all available for us at any place we want by simple connect() method of redux.
Generally we'll maintain a reducer for container where container holds the components which are hydrated by reducer of this container.
It's not an issue even if we maintain a 'reducer' for each component.
And one more good practice is to keep related state say:
cart => cartReducer which in turn accepts all actions on the state of cart like ADD_TO_CART, RESET_CART, CHECKOUT_CART, DELETE_ITEM etc.
And in your case if address, contacts, images etc are related to a single entity, better to maintain a single reducer.
I'm using the ultimate combination of React + Redux + Reselect + Immutable.js in my application. I like the idea of reselect because it lets me keep my state (maintained by the reducers) as simple as possible. I use a selector to calculate the actual state I need which is then fed to the React components.
The problem here is that a small change in once of the reducers causes the selectors to recalculate the whole derived output and as the result also the whole React UI is updated. My pure components don't work. It's slow.
Typical example: The first part of my data comes from server and is basically immutable. The second part is maintained by the client and is mutated using the redux actions. They are maintained by separate reducers.
I use a selector to merge both parts into a single list of Records which is then passed to the React components. But obviously, when I change a single thing in one of the objects, the whole list is regenerated and new instances of Records is created. And the UI is completely re-rendered.
Obviously running the selector every time is not exactly efficient but is still reasonably fast and I'd be willing to make that trade off (because it does make the code way simpler and cleaner). The problem is the actual rendering which is slow.
What I'd need to do would be to deep merge the new selector output with the old one because Immutable.js library is smart enough not to create new instances when nothing was changed. But as selectors are simple functions that do not have access to previous outputs, I guess it's not possible.
I assume that my current approach is wrong and I'd like to hear other ideas.
Probably the way to go would be to get rid of reselect in this case and move the logic into a hierarchy of reducers that would use incremental updates to maintain the desired state.
I solved my problem but I guess there is no right answer as it really depends on a specific situation. In my case, I decided to go with this approach:
One of the challenges that the original selector handled nicely was that the final information was compiled from many pieces that were delivered in an arbitrary order. If I decided to build up the final information in my reducers incrementally, I'd have to make sure to count with all possible scenarios (all possible orders in which the information pieces could arrive) and define transformations between all possible states. Whereas with reselect, I can simply take what I currently have and make something out of it.
To keep this functionality, I decided to move the selector logic into a wrapping parent reducer.
Okay, let's say that I have three reducers, A, B and C, and corresponding selectors. Each handles one piece of information. The piece could be loaded from server or it could originate from the user on the client side. This would be my original selector:
const makeFinalState(a, b, c) => (new List(a)).map(item =>
new MyRecord({ ...item, ...(b[item.id] || {}), ...(c[item.id] || {}) });
export const finalSelector = createSelector(
[selectorA, selectorB, selectorC],
(a, b, c) => makeFinalState(a, b, c,));
(This is not the actual code but I hope it makes sense. Note that regardless of the order in which the contents of individual reducers become available, the selector will eventually generate the correct output.)
I hope my problem is clear now. In case the content of any of those reducers changes, the selector is recalculated from scratch, generating completely new instances of all records which eventually results in complete re-renders of React components.
My current solution looks lite this:
export default function finalReducer(state = new Map(), action) {
state = state
.update('a', a => aReducer(a, action))
.update('b', b => bReducer(b, action))
.update('c', c => cReducer(c, action));
switch (action.type) {
case HEAVY_ACTION_AFFECTING_A:
case HEAVY_ACTION_AFFECTING_B:
case HEAVY_ACTION_AFFECTING_C:
return state.update('final', final => (final || new List()).mergeDeep(
makeFinalState(state.get('a'), state.get('b'), state.get('c')));
case LIGHT_ACTION_AFFECTING_C:
const update = makeSmallIncrementalUpdate(state, action.payload);
return state.update('final', final => (final || new List()).mergeDeep(update))
}
}
export const finalSelector = state => state.final;
The core idea is this:
If something big happens (i.e. I get a huge chunk of data from the server), I rebuild the whole derived state.
If something small happens (i.e. users selects an item), I just make a quick incremental change, both in the original reducer and in the wrapping parent reducer (there is a certain duplicity, but it's necessary to achieve both consistency and good performance).
The main difference from the selector version is that I always merge the new state with the old one. The Immutable.js library is smart enough not to replace the old Record instances with the new Record instances if their content is completely the same. Therefore the original instances are kept and as a result corresponding pure components are not re-rendered.
Obviously, the deep merge is a costly operation so this won't work for really large data sets. But the truth is that this kind of operations is still fast compared to React re-renders and DOM operations. So this approach can be a nice compromise between performance and code readability/conciseness.
Final note: If it wasn't for those light actions handled separately, this approach would be essentially equivalent to replacing shallowEqual with deepEqual inside shouldComponentUpdate method of pure components.
This kind of scenario can often be solved by refactoring how the UI is connected to the state. Let's say you have a component displaying a list of items: instead of connecting it to the already built list of items, you could connect it to a simple list of ids, and connect each individual item to its record by id. This way, when a record changes, the list of ids itself doesn't change and only the corresponding connected component is re-rendered.
If in your case, if the record is assembled from different parts of the state, the selector yielding individual records could itself be connected to the relevant parts of the state for this particular record.
Now, about the use of immutable.js with reselect: this combination works best if the raw parts of your state are already immutable.js objects. This way you can take advantage of the fact that they use persistent data structures, and the default memoization function from reselect works best. You can always override this memoization function, but feeling that a selector should access its previous return value if often a sign that it is in charge of data that should be hold in the state / or that it is gathering too much data at once, and that maybe more granular selectors could help.
It looks like you are describing a scenario very close to the one why I wrote re-reselect.
re-reselect is a small reselect wrapper, which initializes selectors on the fly using a memoized factory.
(Disclaimer: I'm the author of re-reselect).