Is any performance issue with put many items in redux-store?
for example, the store is like this:
{
user:{...},
userDetail:{},
shoppingCart:{},
OrderDetail:{},
...
}
Its keys count is almost 50 items.
I'm using react-redux in my project to store any data (even data that are used in one section of my app and are not share).
It's all about the size of your data, and the way you use it.
data size
You've said you have around 50 items. does each item is an object? does it have 20 properties? maybe 20,000 properties?
I've used redux with around 10,000 complex items (20-30 properties each) and did not experience issues, but your data / behavior might be very different
data usage
How do you treat each change? Is the effect cause a minor change, or do you change the DOM significantly? do you use redux selectors?
Remember that when it comes to performance, Rendering is usually much more costly than updating a data object (even a large one like redux store), so for more cases it's not your state management, it's how you use it.
However, that does not mean you may not encounter problems, so the best way to approach it would be to actually test the problematic scenarios, probably with a benchmark test.
Generally speaking, redux considerated to be a highly-performant state-management system, considering you use it properly:
Use selectors when required, write proper reducers and splitting ui & data effectively to reducers etc.
Related
In a state-managing javascript framework (eg: React), if you have a collection of objects to store in state, which is the more useful and/or performant dataset type to hold them all, an object or an array? Here are a few of the differences I can think of that might come up in using them in state:
Referencing entries:
With objects you can reference an entry directly by its key, whereas with an array you would have to use a function like dataset.find(). The performance difference might be negligible when doing a single lookup on a small dataset, but I imagine it gets larger if the find function has to pore over a large set, or if you need to reference many entries at once.
Updating dataset:
With objects you can add new entries with {...dataset, [newId]: newEntry}, edit old entries with {...dataset, [id]: alteredEntry} and even edit multiple entries in one swoop with {...dataset, [id1]: alteredEntry1, [id2]: alteredEntry2}. Whereas with arrays, adding is easy [...dataset, newEntry1, newEntry2], but to edit you have to use find(), and then probably write a few lines of code cloning the dataset and/or the entry for immutability's sake. And then for editing multiple entries it's going to either require a loop of find() functions (which sounds bad for large lists) or use filter() and then have to deal with adding them back into the dataset afterwards.
Deleting
To delete a single entry from the object dataset you would do delete dataset[id] and for multiple entries you would either use a loop, or a lodash function like _.omit(). To remove entries from an array (and keep it dense) you'd have to either use findIndex() and then .slice(index, 1), or just use filter() which would work nicely for single or multiple deletes. I'm not sure about the performance implications of any of these options.
Looping/Rendering: For an array you can use dataset.map() or even easily render a specialized set on the fly with dataset.filter() or dataset.sort(). For the object to render in React you would have to use Object.values(dataset) before running one of the other iteration functions on it, which I suppose might create a performance hit depending on dataset size.
Are there any points I'm missing here? Does the usability of either one depend perhaps on how large the dataset is, or possibly how frequent the need to use "look up" operations are? Just trying to pin down what circumstances might dictate the superiority of one or the other.
There's no one real answer, the only valid answer is It dependsTM.
Though there are different use-cases that requires different solutions. It all boils down to how the data is going to be used.
A single array of objects
Best used when the order matters and when it's likely rendered as a whole list, where each item is passed from the list looping directly and where items are rarely accessed individually.
This is the quickest (least developer-time consuming) way of storing received data, if the data is already using this structure to begin with, which is often the case.
Pros of array state
Items order can be tracked easily,
Easy looping, where the individual items are passed down from the list.
It's often the original structure returned from API endpoints,
Cons of an array state
Updating an item would trigger a render of the full list.
Needs a little more code to find/edit individual items.
A single object by id
Best used when the order doesn't matter, and it's mostly used to render individual items, like on an edit item page. It's a step in the direction of a normalized state, explained in the next section.
Pros of an object state
Quick and easy to access/update by id
Cons of an object state
Can't re-order items easily
Looping requires an extra step (e.g. Object.keys().map)
Updating an item would trigger a render of the full list,
Likely needs to be parsed into the target state object structure
Normalized state
Implemented using both an object of all items by id, and an array of all the id strings.
{
items: {
byId: { /**/ },
allIds: ['abc123', 'zxy456', /* etc. */],
}
}
This becomes necessary when:
all use-cases are equally likely,
performance is a concern (e.g. huge list),
The data is nested a lot and/or duplicated at different levels,
re-rendering the list as undesirable side-effects
An example of an undesirable side-effect: updating an item, which triggers a full list re-render, could lose a modal open/close state.
Pros
Items order can be tracked,
Referencing individual items is quick,
Updating an item:
Requires minimal code
Doesn't trigger a full list render since the full list loops over allIds strings,
Changing the order is quick and clear, with minimal rendering,
Adding an item is simple but requires adding it in both dataset
Avoids duplicated objects in nested data structures
Cons
Individual removal is the worse case scenario, while not a huge deal either.
A little more code needed to manage the state overall.
Might be confusing to keep both state dataset in sync.
This approach is a common normalization process used in a lot of places, here's additional references:
Redux's state normalization is a strongly recommended best practice,
The normalizr lib.
I am using the react-redux for one of my app, The design is quite difficult and performance required is very high. its actually wyswyg builder.
We have been using the react from last 2 months, Then we moved to the react-redux for the separation of code and improve maitainance, code readability and the parent-child approach headache ofc.
So, I have an array which has quite complex structure
This is how my state look a like:
const initialState = {
builder:{},
CurrentElementName:"",
CurrentSlideName:"",
.......
}
As redux recommend to have less data in particular object as possible, I have another 8-9 reducer which are divided from the main state.
My problem: builder object is very complex which has almost 3-4 levels down, objects and arrays, this all are managed runtime.
So, on the componentdidmount my application will call the server get the data and fill the builder:{}
builder:{
slidedata:[{index:0,controName:'button',....},{index:0,controName:'slide',....}],
currentSlideName:'slide1',
currentElementName:'button1'
}
This builder object is quite complex and depends on the user actions like drag and drop, changing the property, changing events, changing position this builder object is being changed by the reducer
let clonedState= JSON.parse(JSON.stringify(state));
//doing other operations
Every time some thing changes this object needs to perform certain complex operations, for ex, adding the new slide will do certain operations and add the slide to the current array called slidedata.
What is the best practice to fast this things up? am I doing something wrong?
I am not sure what is the wrong in this code, and as redux recommend I can not use the flat structure for this particular array as its managed run-time.
I am sure that component has the data which the component wants.
Is there any way to handle the big data? This iterations and changing the state is killing my performance.
Based on my current experience with React-Redux framework, Re-select and ImmutableJS make a perfect combination for your requirement.
Re-Select uses memoization technique on Javascript objects and have list of API's specifically dealing with these kind of large set of Javascript objects thus improving performance. Read the docs.
Note: One should wisely read the documentation before using this setup to churn the best of these tools.
You can either create your own boilerplate code using above libraries or use the one which i am currently using in my project.
https://www.reactboilerplate.com/
This boilerplate is specifically designed for performance. You can customize it based on your needs.
Hope this helps!
Problem
I am trying to design webapp with a fairly complex state, where many single actions should trigger multiple changes and updates across numerous components, including fetching and displaying data asynchronously from external endpoints.
Some context and background:
I am building a hybrid cytoscape.js / redux app for modeling protein interactions using graphs.
My Redux store needs to hold a representation of the graph (a collection of node and edge objects), as well as numerous filtering parameters that can be set by the user (i.e only display nodes that contain a certain value, etc).
The current implementation uses React.js to manage all the state and as the app grew it became quite monolithic, hard to reason about and debug.
Considerations and questions
Having never used Redux before , I'm struggling a bit when trying to conceptually design the new implementation. Specifically, I have the following questions / concerns:
Cytoscape.js is an isolated component since it's directly manipulating the DOM. It expects the state (specifically the node and edge collections) to be of a certain shape, which is nested and a little hard to handle. Since every update to any node or edge object should be reflected graphically in cytoscape, should I mirror the shape it expects in my Redux store, or should I transform it every time I make an update? If so, what would be a good place to do it? mapStateToProps or inside a reducer?
Certain events, such as selecting nodes and/or edges, crate multiple side-effects across the entire app (data is fetched asynchronously from the server, other data is extracted from the selection and is transformed / aggregated, some of it derived and some of it from external api calls). I'm having trouble wrapping my head around how I should handle these changes. More specifically, let's say a SELECTION_CHANGE action is fired. Should it contain the selected objects, or just their IDs? I'm guessing IDs would be less taxing from a performance point. More importantly, how should I handle the cascade of updates the SELECTION_CHANGE actions requires? A single SELECTION_CHANGE action should trigger changes in multiple parts of the UI and state tree. Meaning triggering multiple actions across different reducers. What would be a good way to batch / queue / trigger multiple actions depending on SELECTION_CHANGE?
The user needs to be able to filter and manipulate the graph according to arbitrary predicates. More specifically, he should be able to permanently delete \ add nodes and edges, and also restrict the view to a particular subset of the graph. In other words, some changes are permanent (deleting \ adding or otherwise editing the graph) while others relate only to what is shown (for example, showing only nodes with expression levels above a certain threshold, etc). Should I keep a separate, "filtered" copy of the graph in my state tree, or should I calculate it on the fly for every change in the filtering parameters? And as before, if so, where would be a good place to perform these filtering actions: mapStateToProps, reducers or someplace else I haven't thought of?
I'm hoping these high-level and abstract questions are descriptive enough of what I'm trying to achieve, and if not I'll be happy to elaborate.
The recommended approach to Redux state shape is to keep your state as minimal as possible, and derive data from that as needed (usually in selector functions, which can be called in a component's mapState and in other locations such as thunk action creators or sagas). For nested/relational data, it works best if you store it in a normalized structure, and denormalize it as needed.
While what you put into your actions is up to you, I generally prefer to keep them fairly minimal. That means doing lookups of necessary items and their IDs in an action creator, and then looking up the data and doing necessary work in a reducer. As for the reducer handling, there's several ways to approach it. If you're going with a "combined slice reducers" approach, the combineReducers utility will give each slice reducer a chance to respond to a given action, and update its own slice as needed. You can also write more complex reducers that operate at a higher level in the state tree, and do all the nested update logic yourself as needed (this is more common if you're using a "feature folder"-type project structure). Either way, you should be able to do all your updating for a single logical operation with one dispatched action, although at times you may want to dispatch multiple consecutive actions in a row to perform a higher-level operation (such as UPDATE_ITEM -> APPLY_EDITS -> CLOSE_MODAL to handle clicking the "OK" button on an editing popup window).
I'd encourage you to read through the Redux docs, as they address many of these topics, and point to other relevant information. In particular, you should read the new Structuring Reducers section. Be sure to read through the articles linked in the "Prerequisite Concepts" page. The Redux FAQ also points to a great deal of relevant info, particularly the Reducers, Organizing State, Code Structure, and Performance categories.
Finally, a couple other relevant links. I keep a big list of links to high-quality tutorials and articles on React, Redux, and related topics, at https://github.com/markerikson/react-redux-links . Lots of useful info linked from there. I also am a big fan of the Redux-ORM library, which provides a very nice abstraction layer over managing normalized data in your Redux store without trying to change what makes Redux special.
I'm trying to wrap my head around Redux and how to implement it in a React Native app.
I get the general idea and I like it. But I'm not quite sure how to structure my store. I'll try to give an example with two scenes from the app.
ProjectListScreen:
A list of projects built with a ListView component. Each row exposes about 5 fields from each project object.
ProjectScreen:
A ScrollView showing all fields for a specific project. The project object can be quite large and not entirely flat. For example it holds an array of UUIDs pointing to images.
So, should I have a single reducer to handle the complete "Projects" or should I have one reducer for ProjectList and one for Projects? I.e. should I think in terms of the real domain or in terms of views/screens in the app?
I suspect that the answer will be to mimic the domain. But what if there are 1000 projects in the list? I need to load 1000 projects into the store including all fields for each project. But I will only need five of those fields to render the ListView. Only a couple of projects will probably be loaded fully because the user won't open all 1000 projects in a ProjectScreen. A change in one project will force a copy of the while array in order to stay immutable.
I don't want to get stuck in premature optimizing, but I'd like to get the structure of the store somewhat right from start. I know I could use Immutable.js to optimize the updating of items in the list, but this would give me non JS objects to work with, which feels kind of cumbersome.
I'd rather use seamless-immutable, but I don't think this kind of partial update of a large list will be faster with SI than copying the list.
I'd love to hear that performance will be a non-issue compared with the UI rendering and other tasks. This would make it a no-brainer to go with a domain structure.
Domain, absolutely. Your store structure should totally reflect the actual data you're working with. Your UI layer should then do any transformations needed on a per-component basis, primarily in your mapStateToProps functions. Focus on the actions and behavior that make up your application at its core. (This should also lead to a better testing setup as well.)
The best practice for organizing data that is nested or relational is to normalize it, similar to tables in a database. I've written some prior answers that describe this concept to some extent, and link to some further articles and discussions ( [0], [1], [2] ).
I generally advise against using Immutable.js, at least to start with. It has its uses, and can offer some performance improvements if your app is configured correctly, but also has a number of potential performance pitfalls as well ( [3] ). I would suggest sticking with plain JS objects. There's a variety of ways to use those in an immutable fashion. I have a list of articles describing those approaches ( [4] ), as well as a list of libraries that can make immutable use of plain JS objects easier ( [5] ).
Finally, I'm actually just starting to work on a new page for the Redux docs that describes best practices for structuring reducers. It'll take some time to get it written and polished, but you might want to keep an eye on it. The issue is at [6], and that has a link to my current WIP article branch.
[0] https://stackoverflow.com/a/38105182/62937
[1] https://stackoverflow.com/a/38017227/62937
[2] https://stackoverflow.com/a/37997192/62937
[3] https://github.com/markerikson/react-redux-links/blob/master/react-performance.md#immutable-data
[4] https://github.com/markerikson/react-redux-links/blob/master/immutable-data.md
[5] https://github.com/markerikson/redux-ecosystem-links/blob/master/immutable-data.md
[6] https://github.com/reactjs/redux/issues/1784
edit:
As a follow-up, the Redux docs now include a "Structuring Reducers" section, which has a variety of information on this topic.
So I started learning React a week ago and I inevitably got to the problem of state and how components are supposed to communicate with the rest of the app. I searched around and Redux seems to be the flavor of the month. I read through all the documentation and I think it's actually a pretty revolutionary idea. Here are my thoughts on it:
State is generally agreed to be pretty evil and a large source of bugs in programming. Instead of scattering it all throughout your app Redux says why not just have it all concentrated in a global state tree that you have to emit actions to change? Sounds interesting. All programs need state so let's stick it in one impure space and only modify it from within there so bugs are easy to track down. Then we can also declaratively bind individual state pieces to React components and have them auto-redraw and everything is beautiful.
However, I have two questions about this whole design. For one, why does the state tree need to be immutable? Say I don't care about time travel debugging, hot reload, and have already implemented undo/redo in my app. It just seems so cumbersome to have to do this:
case COMPLETE_TODO:
return [
...state.slice(0, action.index),
Object.assign({}, state[action.index], {
completed: true
}),
...state.slice(action.index + 1)
];
Instead of this:
case COMPLETE_TODO:
state[action.index].completed = true;
Not to mention I am making an online whiteboard just to learn and every state change might be as simple as adding a brush stroke to the command list. After a while (hundreds of brush strokes) duplicating this entire array might start becoming extremely expensive and time-consuming.
I'm ok with a global state tree that is independent from the UI that is mutated via actions, but does it really need to be immutable? What's wrong with a simple implementation like this (very rough draft. wrote in 1 minute)?
var store = { items: [] };
export function getState() {
return store;
}
export function addTodo(text) {
store.items.push({ "text": text, "completed", false});
}
export function completeTodo(index) {
store.items[index].completed = true;
}
It's still a global state tree mutated via actions emitted but extremely simple and efficient.
Isn't Redux just glorified global state?
Of course it is. But the same holds for every database you have ever used. It is better to treat Redux as an in-memory database - which your components can reactively depend upon.
Immutability enables checking if any sub-tree has been altered very efficient because it simplifies down to an identity check.
Yes, your implementation is efficient, but the entire virtual dom will have to be re-rendered each time the tree is manipulated somehow.
If you are using React, it will eventually do a diff against the actual dom and perform minimal batch-optimized manipulations, but the full top-down re-rendering is still inefficient.
For an immutable tree, stateless components just have to check if the subtree(s) it depends on, differ in identities compared to previous value(s), and if so - the rendering can be avoided entirely.
Yes it is!!!
Since there is no governance of who is allowed to write a specific property/variable/entry to the store and practically you can dispatch any action from anywhere, the code tends to be harder to maintain and even spaghetti when your code base grows and/or managed by more than one person.
I had the same questions and issues with Redux when I started use it so I have created a library that fix these issue:
It is called Yassi:
Yassi solves the problems you mentioned by define a globally readable and privately writable store. It means that anyone can read a property from the store (such as in Redux but simpler).
However only the owner of the property, meaning the object that declare the property can write/update that property in the store
In addition, Yassi has other perks in it such as zero boilerplate to declare entry in the store by using annotations (use #yassit('someName'))
Update the value of that entry does not require actions/reducers or other such cumbersome code snippets, instead just update the variable like in regular object.