I am fairly new to redux and redux-toolkit, but I am fairly familiar with the whole concept of stores (coming from a vuex background).
I have an issue organizing a large state with lots of dependencies between the objects. My current approach is to use a structure similar to RDBMS where each object has its own ID and other objects reference it through that ID. This way, there are no deeply nested objects.
My current problem is how to organize a large state with lots of dependencies and lots of types of objects (type of object = "table"). I could put all of the objects into a single slice, but this would make that slice incredibly large.
Another approach is to separate each of the object types into different slices, with a single slice for each object type. This presents the problem that accessing the state of another slice is not easily done but is required to update that state in order to keep the state consistent (i.e. avoid broken references).
Is there a good, common approach on how to structure a large state with a lot of dependencies?
Where I work we decided to go with RTK and to have one slice per entity/object related to a table in the backend (users, customers, products, etc). This is working fine.
You can access the state of another slice by using the thunkAPI object as the second parameter of the payloadCreator callback of the createAsyncThunk function. This object contains multiple methods. One of them is getState :)
Related
I have at least two approaches to solve a problem.
Repreform calculations inside views on each update (map, filter, find)
Keep an "CurrentState" object inside my redux state.
I choose to create a CurrentState object that stores my calculated result (It calculates the results inside the reducer function).
Approach 2 saves processor calculations, but it feels dirty.
is it considered an antipatern to have a CurrentState object (updated from the reducer) inside the state?
Thank you in advance!
Not totally clear from your question - but I assume that you are talking about situation, that you can compute "result" from other data in your store and asking if storing it (redundantly) in store is good pattern.
Well, generally I would not recommend it as keeping redundant data in store can lead to inconsistent data bugs - if you forgot to keep your data in sync (e.g. when you or someone else working on the project would change one data and forget to change the order place).
The standard patter for this is usually to use selectors and memonization (see https://github.com/reactjs/reselect). The idea is to keep only normalized data in your store but to use selectors in your views. Selectors are responsible to "cache" (memonize) extensive computation. Another advantage of selectors is that it provides level of indirection for your application and you can easily evolve your state (as the project grows) without affecting your whole application. On the other hand for small and one time projects selectors can be just "another" boilerplate - but in general I recommend to use them.
This was a hard anti-pattern.
If you are reading this chances are you don't fully understand redux and I would like to recommend
https://github.com/leoasis/redux-immutable-state-invariant
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 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 ReactJs with Redux and on some tutorials and codes I see people suggesting and using normalizr to keep the state flat. But what is the real advantage in keeping it flat ? Will I encounter any problems if I don't ? Is it necessary ?
Three main reasons:
Updating nested Javascript objects immutably generally results in uglier code that is harder to maintain, unless you use a utility library to wrap up the process
Immutably updating nested data requires that you return new copies of all items in the nesting hierarchy. Since components generally do shallow-equality reference comparisons on data to see if they need to update, updating nested data usually means that more objects are updated, and more components will probably have to re-render even if the actual data isn't different.
Flat data, and in particular normalized data, enables some more optimized approaches for defining components (such as a list where each list item component is itself connected, given an item ID as a prop, and is responsible for looking up its own item's data by that ID)
I'm assuming that by keeping it flat, you mean not having nesting in your state object.
It is not advisable to have nesting in your state because you have to keep changing your state according to some events.
If you look at redux documentation, they want you to have pure reducers. And part of making your function pure is not modifying it's arguments.
When you have lots of nesting it's difficult to change state without inadvertently modifying the state object because all JS objects are passed by reference. When you have a lot of nesting you have to make deep copies of the state object before modifying it.
I'm new to Redux - and I'm really trying to get the big picture of using functional programming to make unidirectional data more elegant.
The way I see it- each reducer is taking the old state, creating a new state without mutating the old state and then passing off the new state to the next reducer to do the same.
I get that not causing side effects helps us get the benefits of a unidirectional flow of data.
I just really don't get what is so important about not mutating the old state.
The only thing I can think of is maybe the "Time-Traveling" I've read about because, if you held on to every state, you could perform and "undo".
Question:
Are there other reasons why we don't want to mutate the old state at each step?
Working with immutable data structures can have a positive impact on performance, if done right. In the case of React, performance often is about avoiding unnecessary re-rendering of your app, if the data did not change.
To achieve that, you need to compare the next state of your app with the current state. If the states differ: re-render. Otherwise don't.
To compare states, you need to compare the objects in the state for equality. In plain old JavaScript objects, you would need to deep compare in order to see if any property inside the objects changed.
With immutable objects, you don't need that.
immutableObject1 === immutableObject2
basically does the trick. Or if you are using a lib like Immutable.js Immutable.is(obj1, obj2).
In terms of react, you could use it for the shouldComponentUpdate method, like the popular PureRenderMixin does.
shouldComponentUpdate(nextProps, nextState) {
return nextState !== this.state;
}
This function prevents re-rendering, when the state did not change.
I hope, that contributes to the reasoning behind immutable objects.
The key of the "no-mutations" mantra is that if you can not mutate the object, you are forced to create a new one (with the properties of the original object plus the new ones).
To update the components when an action is dispatched, Redux connector checks if the object is different, not if the properties have changed (which is a lot faster), so:
If you create a new object, Redux will see that the object is not the same, so it will trigger the components updates.
If you mutate the objet that it is already in the store (adding or changing a property, for example) Redux will not see the change, so it will not update the components.
I'm pretty new to Redux (and React.js) too, but this is what I understand from learning this stuff.
There are several reasons why immutable state is chosen over the mutable one.
First of all, mutation tracking is pretty difficult. For example when you are using a variable in several pieces of code and the variable can be modified in each of this places, you need to handle each change and synchronize results of mutation.
This aproach in many cases leads to bidirectional data flows. Pieces of data are flowing up and down across the functions, variables and so on. Code starts beeing polluted by if-else constructions that are oly responsible for handling state changes.
When you add some asynchronous calls your state changes can be even harder to track.
Of course we can subscribe to data events (for example Object.observe), but it can lead to situation that some part of application that missed change stays out of sync with other part of your program.
Immutable state helps you to implement unidirectional data flow that helps you to handle all changes. First of all data flows from top to bottom. That means all changes that were applied to the main model are pushed to the lower components. You can always be sure that the state is the same in all places of the application, because it can be changed only from one place in the code - reducers.
There is also one thing worth of mentioning - you can reuse data in several components. State cannot be changed (a new one can be created), so it's pretty safe to use same piece of data in several places.
You can find more information about pros and cons of mutability (and about the reason why it was chosen as a main approach of Redux) here:
Pros and Cons of using immutability with React.js
React.js Conf 2015 - Immutable Data and React
Immutable Data Structures and JavaScript
Introduction to Immutable.js and Functional Programming Concepts
Why immutable collections?
Redux checks if the old object is the same as the new object by comparing the memory locations of the two objects. If you mutate the old object’s property inside a reducer, the “new state” and the “old state” will both point to the same object and Redux will infer that nothing has changed.
No reasons. The are no any fundamental reasons that shouldComponentUpdate "pure render" optimization can't work with mutable state containers. This library does it, for instance.
https://github.com/Volicon/NestedReact
With immutable data the reference to the data structure itself can be used as version token. Thus, comparing the references you're comparing the versions.
With mutable data you will need to introduce (and compare) separate version tokens, which is hard to do manually but can easily be achieved with smart "observable" objects.
There are several reasons.
Because of the history (undo/redo) feature.
You can use the history feature also for debugging.
Race conditions: Lets say you have a service that logs some state data
after 1s. If you change the state before the service has logged the
data the service will log the wrong data. Of course you could copy
the state before passing it to the service, but it's easy to enforce
this rule if you do it in a mutation/method in one place, the store, the
single source of truth.