React Redux, connecting store to 1000 of tiny components - javascript

I have run into a performance issue with react redux, and I have been reading a bit about, and per what I ended up with, it "seems" like I am doing it all "correct".
I have a situation where I have a production line tracking system, and for each "project" there is 12 steps that it goes through.
I have about 60-100 projects going on every week, split into days, easily visible on 1 view.
Now the problem lies in the fact that, each of those 12 steps, are individual components that I connected up using the React Redux Connect function, which basically maps the flat store state of all the different steps, and searched out that exact step from the store, which contains data about when it was done, its status etc, and then it throws that into it as a prop, and uses it to render.
Now, everytime I create an update into the store of the list of steps, it obviouslly rerenders those aprox 1000 components, and checks whether or not they need to rerender, which only 1 of them then does, the one that I clicked on, lets say.
However, the whole computing part of looping through 1000 mapToState functions takes time, and slows down the app and makes it irresponsive.
Is there a smarter way to go about connecting up the components to the store.
As a note, I have thought about this long before writing this, and I have also tried to map up only each project (each set of 12 steps), and have them then render pure components based on that as a parent, sending down each individual step to the child component with the data, however, I don't get any better result.
Thanks in advance for anyone who can help with some guidance or pushing me in the right direction.
Vincent Rye

I'm currently in this situation and am also looking for a definitive answer, but I'll share what I've come up with so far:
For a web app to hit a target of 60fps you have a per-frame budget of 16.67ms per frame.
If you have 1,000 connected components there's some amount of redux bookkeeping (like running mapStateToProps) that will happen on every store update for every component, and to stay within a frame budget of 16.67ms you'll need that bookkeeping to happen within 0.017ms (or 17,000ns) on average.
From experience, that has been hard to achieve for us.

Related

How can I tell Redux not to update React state yet?

I am currently dealing with a very large table of data. Some actions the user can take are quite complex - complex enough that I might end up dispatching a hundred actual actions to Redux, many of which will depend on the state being updated by previous actions, and causing a hundred state changes... which will result in the page seeming to lock up as numerous things in a very large table are rendered a hundred times, even though none of these updates will be individually meaningful to the user (or actively confusing)
Is there a way to delay Redux/React from seeing these changes - to say "okay, don't bother pestering React about this stuff, don't recalculate any props, don't do anything but throw this stuff through the reducers until it's done and I tell you it's done, and then return to normal behaviour" ?
I know I could set some React state property and then have a shouldUpdateComponent in each of my many components, but I was hoping there was a solution that involved less duplicate code scattered across dozens of files and perhaps even a bit more efficiency of avoiding calling the same exact function dozens of times per update.
Any suggestions?
Dan Abramov himself wrote on twitter an example of how to do this using batched actions and a higher order reducer.
https://twitter.com/dan_abramov/status/656074974533459968?lang=en
The gist of the idea is to wrap the actions you want to batch in another action, and define a higher order reducer (a reducer that returns another reducer, eg. redux-undo) that will apply all these actions when it handles the batched action update.

Redux performance with lots of changes to the store every second

I'm creating an audio-visual app for performances at clubs/parties. It involves webGL animation that runs at 60fps.
The animation responds to multiple parameters that could be constantly changing every second (e.g. The size of a spinning cube could be pulsing to music). As an example, there may be 20 parameters, all changing sixty times per second. These parameters are represented in the UI as numbers/visual bars.
I'm using React/Flux/NWJS to do this and it works fine. However I really like Redux and would like to change the data flow to the Redux model.
My question is:
Will updating the store in an immutable way (e.g. replicating it for each change) affect performance, when it could be changing more than 60 times per second? If so, is there a way I can bypass this for certain parts of the app and just use Redux for the less frequent changes to the app.
If you're using WebGL for your visuals, you may keep Redux but skip React all. Redux is independent from React, you are free to use its semantics and then do something when the Store is changed by registering a callback with subscribe.
http://es.redux.js.org/docs/api/Store.html#subscribe
It's not clear to me the aspect of your app, will be both the visualization with WebGL and the sliders/controls present at the screen at the same time?
If they are, you can still have a React app hosting your UI controls and a separate DIV containing your canvas. The React part will use standard Redux to keep the parameters state, and your WebGL independent code should read from the store on every requestAnimationFrame and render your scene.
You could also use a Redux middleware that queues actions and dispatch on requestAnimationFrame, as suggested in the docs here (see the rAF scheduler example)
http://redux.js.org/docs/advanced/Middleware.html#seven-examples

How to deal with component state with redux?

I have been using vanilla React for a while, and have now decided to take a closer look at Redux for a new project I am doing.
At first I got the impression that all user activity should result in actions, with one of the main reasons being that you would be able to reconstruct any application state by just playing back the appropriate actions.
The problem with this, however, is that you put a lot of stuff in the store that in reality does not feel like application state. Stuff like "If I focus on this input, the label turns green" does not seem like state fitted for being represented in the application state of an application that is potentially composed by hundreds of components. These things make total sense with the typical todo-tutorial, but it can be difficult to see how it will turn out in a more complex scenario.
Then I read some more, and found that the general opinion, backed by creator Dan Abramov, is that you should usually combine local component state with the application state (store). "Whatever seems least awkward" seemed to be the rule of thumb for where to store state.
On one hand this makes total sense: The things that are really application state, and are relevant for multiple components should be in the store, while the strictly presentational details that only concerns one single component should be handled using normal react state. On the other hand this approach confuses me a bit, because of what I wrote in the beginning: Isn't a big part of the point with redux that you avoid having the state distributed among the components, and that you are able to recreate state by just storing the actions?
I hope someone can shed some light on this concern, because it has been bothering me, and it is something I think I should get a solid opinion about before trying to build something complex with redux.
What state you put where is entirely up to you. Sometimes it may make sense to put everything in Redux, sometimes it may make sense to keep stuff in a component. I recently saw some good rules-of-thumb:
Do other parts of the application care about that data?
Do you need to be able to derive further data from that data?
Is the same data being used to drive multiple components/features?
Is there value to you, to being able to restore the state to a given point in time (ie: time travel / debugging)?
Do you want to cache the data, ie: reload it from state if it's already there instead of requesting it again?
(Credit to https://www.reddit.com/r/reactjs/comments/4w04to/when_using_redux_should_all_asynchronous_actions/d63u4o8 for that list.)
Also see the Redux FAQ on this topic: http://redux.js.org/docs/FAQ.html#organizing-state-only-redux-state .

Component Entity System Entity Specific Data

I've been writing a Component Entity System in javascript for a while now but I keep returning to a root issue.
How do you handle entity specific - that is to say a single instance or single type - functionality?
Here's the current situation:
The way I have structured things, when an item entity is stored in inventory by another entity it isn't destroyed, merely stripped of most of its components. This is so that if it is dropped, or perhaps retrieved for use, it can be reactivated with its old state. The components that are stripped are stored in an InstanceDataComponent attached to the entity (this is just a JSON object).
There is a small system for managing the internals of whether an item can be picked up and adding an inventory record with a hash, quantity, and id for the thing being stored but something needs to manage the transformation of that entity from its "item" state to its "stored" state. What should do this? It seems to me that the details of which component to remove and what data to alter will need to be nearly unique for each item.
Suppose that in the future I want an entity to switch between two behaviors on the fly. For example, to pace to and fro until it is disturbed then pathfind to the player. What will handle that transition?
I get the feeling I've got a fundamental misunderstanding of the issues and typical architecture here. What would be a clean way to handle this? Should I perhaps add a component for each set of behavior transitions? Wouldn't that end up with far too many components that are glorified callback wrappers? Or am I missing something about how an entity should be altered when it is stored in inventory?
Some thoughts for others who might be going through this situation.
My current solution (after several iterations) is to fire a global event e.g. itemPickupSystem:storedItem and an entity can attach handlers for any events inside its factory method. This isn't scalable, for a number of reasons. I've been considering moving those events into a queue to be executed later.
My factory methods have turned into a hodgepodge of callback definitions and things are degrading into callback hell. In addition, this events system has to go, it is the only part of the entire system that breaks the serial nature of the game loop. Until now each system fired in a defined order and all logic resided inside those systems. Now I can't guarantee that an entity will be in a specific state because those callbacks could have been fired at different points. Finally, because execution is being turned over carte blanche to code that isn't part of the core functionality there is no way to know how large that call stack will get when an event is fired.
Sometimes it's easiest to think of this problem in terms of pragmatic network replication, and the boundaries between components come naturally.
Let's say that your actor can both wield, and store, a sword.
I would not anticipate a 'transform' from an inventorySword into a presentationSword, but rather that there's a natural delineation between an 'inventoryItem' and a 'swordPresentation'.
On the server, each player would be assigned a list of items in their inventory. Each item would have a unique id for the world. The inventory item might be derived as 'SwordItem' and have properties for SwordType and Condition%
On the client, a 'swordPresentation' component might handle the job of which mesh to display, which socket to attach animation data to when displayed via a 1st person camera, and how to smooth animation transitions. But none of that matters to the actual state of the game, it's simply how our client is seeing the world.
Potentially, if you were distributing the state of the game to each client all that you would pass over the network would be the current player's inventory, and for the other players, which item each player has currently equipped and where they are (assuming they're in eyesight)
So, consider creating a factory that creates a 'swordPresentation' based off of an inventory item, finding the bare minimum you can pass in as parameters to create a representation of the component (maybe it's sword type, sword % condition, etc).
Whatever that bare minimum is what you want to serialize as your inventory item.
Establishing a clear delineation between replicated data means better performance, fewer vulnerabilities when you're writing a multiplayer game. When you're writing a single-player game, it'll help you understand what goes into a save file.

React + Redux performance optimization with componentShouldUpdate

I have a react/redux application which has become large enough to need some performance optimizations.
There are approx ~100 unique components which are updated via websocket events. When many events occur (say ~5/second) the browser starts to slow down significantly.
Most of the state is kept in a redux store as Immutable.js objects. The entire store is converted to a plain JS object and passed down as props through the component tree.
The problem is when one field updates, the entire tree updates and I believe this is where there is most room for improvement.
My question:
If the entire store is passed through all components, is there an intelligent way to prevent components updating, or do I need a custom shouldComponentUpdate method for each component, based on which props it (and its children) actually use?
You really don't want to do things that way. First, as I understand it, Immutable's toJS() is fairly expensive. If you're doing that for the entire state every time, that's not going to help.
Second, calling toJS() right away wastes almost the entire benefit of using Immutable.js types in the first place. You really would want to keep your data in Immutable-wrapped form down until your render functions, so that you get the benefit of the fast reference checks in shouldComponentUpdate.
Third, doing things entirely top-down generally causes a lot of unnecessary re-rendering. You can get around that if you stick shouldComponentUpdate on just about everything in your component tree, but that seems excessive.
The recommended pattern for Redux is to use connect() on multiple components, at various levels in your component tree, as appropriate. That will simplify the amount of work being done, on several levels.
You might want to read through some of the articles I've gathered on React and Redux Performance. In particular, the recent slideshow on "High Performance Redux" is excellent.
update:
I had a good debate with another Redux user a couple days before this question was asked, over in Reactiflux's #redux channel, on top-down vs multiple connections. I've copied that discussion and pasted it in a gist: top-down single connect vs multiple lower connects.
Also, yesterday there was an article posted that conveniently covers exactly this topic of overuse of Immutable.js's toJS() function: https://medium.com/#AlexFaunt/immutablejs-worth-the-price-66391b8742d4. Very well-written article.

Categories

Resources