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.
Related
I have recently started working in VueJS and I have been instructed by one of the lead devs to never combine emit events and vuex store. Basically, if the project will use a store, take all the events/state through the store.
From one point of view I can understand this, but there are a lot scenarios in which emiting an event is so much faster than taking everything through the store.
Is this the best practice by not combining Vuex and emit events?
As a lead developer myself using Vue, this arbitrary rule is simply narrow-minded.
When using Vuex and deciding to use an emit or not, I look at the relationship. If I have a component that only needs to interact with its parent, then I use an emit. It keeps the store cleaner and the relationships clearer. Your lead is not making scalable or maintainable code.
If he/she argues you shouldn't use emits when you have a store, then following that logic, you shouldn't use props ever either. That is equally nonsensical.
Once you start working with applications that have several children down, you'll realize that jamming the store with every variable you'll need just for a few components way down the hierarchy creates a horrible mess of things.
I disagree with your Lead. Vuex should only be used for data that is truly global. Any data/events that are only shared between a component and its child should go through emit/props.
While there can/should be debate about what should use the store vs props and emit, a blanket "always use store" is almost certainly wrong and will lead to a needlessly bloated store.
If I have a class with a bunch of properties, it seems like a hassle to put the properties that I modify inside (for example) this.state.myProp1 instead of this.myProp1. and then I need to make a copy of whatever property it is before I send it off to setState (because I can't mutate it directly). Like an array of objects for example.
At some point I display some of these properties so that means that I need to hold all my class properties inside this state, and then keep track of what I need to refresh, instead of refreshing the whole thing.
I almost prefer to use this.forceUpdate() instead and have my render() refer to class properties directly. Why does react "make" people use this.state and setState. Is it for performance reasons?
setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses.
So basically setState is there to tell react when to re-render. Also setState behaves asynchronously, and updates the state only when necessary. So if you call setState multiple times immediately it will update only on the last one so as to minimize the number of re-renders and be less taxing on the browser. If there was no setState and react re-rendered every time the data changed, the browser experience would be terrible.
You don't have to use React this.state and setState if you don't want to. You can always use redux or mobx to manage the state.
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made.
And yeah, that's why you've to make a copy of whatever property it is before I send it off to setState
IMHO, component state is an elegant concept for some special case. for example when you want to monitor the content change of a text input on live, that is, not after hit save or submit button. under such situation, a component state would be ideal place to store the temporary input and you will not get overhead to use redux action to respond on the every incomplete input. it is just like a buffer to provide performance improvement.
1. Reasons behind setState
The main reason for having to use setState is its asynchronous execution, from the react docs:
React intentionally “waits” until all components call setState() in their event handlers before starting to re-render. This boosts performance by avoiding unnecessary re-renders.
If the state object was updated synchronously it would cause consistency issues, since props are not updated until the parent component is re-rendered, so, mutating this.state directly would lead to inconsistency between props and state.
For further reference, you can check this this Github thread.
2. Reasons behind this.state
The main advantage of the state object is its immutability which couldn't be accomplished with component properties, also there is the separation of responsibility between props and state, which is way easier to handle and update individually.
Why does react "make" people use this.state and setState. Is it for performance reasons?
That's a good question - the existing answer from J. Pichardo is quite correct but I wanted to address the why in a little more depth - as opposed to what or how.
Really a better question is - why does React exist? According to this article
React’s one-way data flow makes things much simpler, more predictable, and less bug-prone. One way data flow greatly simplifies your thinking about state because no view can ever mutate the state directly. Views can only send actions up to the global state store.
Really theres a whole bunch of reasons why React has it's place as a useful UI library. But in regards to your question - uni-directional data flow - this is the main reason.
relational UIs get complex. When an app has to consume, display and update even just a modest amount of relational data and have that information displayed across multiple elements, things can get messy fast.
Using state and props the way that React does allows one to differentiate and guarantee whether a piece of the UI will just receive data to display or whether it might change it too.
If you store that data just in a random key you have no real way of knowing whether the value is changed and what changed it. By separating out your state from your component in this way, it decouples the data from the element and makes it much easier to share data between elements and also change that data in different ways.
according to this article on coupled object interfaces a tightly coupled entity is bad because:
A tightly Coupled Object is an object that needs to know about other objects and are usually highly dependent on each other's interfaces. When we change one object in a tightly coupled application often it requires changes to a number of other objects. There is no problem in a small application we can easily identify the change. But in the case of a large applications these inter-dependencies are not always known by every consumer or other developers or there is many chance of future changes.
This very much is applicable in UI development also. In my opinion this is why not setting state is going to cause you some pain later on.
I am considering moving my reducers from plain JS to immutable.js.
It will take a few days to understand immutable.js api and do the refactor with the tests and I want to give some thought to whether this transition is necessary. My motivation is the fact I am currently duplicating the state on every change:
let newState = {...state};
This is expensive and leads me to forget cloning deep objects from time to time.
Googling the issue for the last days I still don't understand whether moving my reducers to immutable.js will result in a performance hit and whether I would need to go through my components and containers and use state.toJS() on each one.
What is the performance hit on moving to immutable.js? especially when I use undo and keep multiple steps. Will I have to use .toJS() every time I need data for my components/containers?
Short answer about performance: it depends. To quote Dan Abramov here,
In short: create a sample app that imitates the kinda of data size and change speed you expect in your app, and profile it. No other way to tell if dropping Immutable is going to work for you.
One of the major benefits to using a library like immutable is as you mentioned, it prevents you from forgetting to clone deep objects from time to time, which can lead to really nasty bugs that are hard to track down. Likewise, undo can be much easier with immutable if you keep track of previous states, whereas they are much much more involved without an immutable library since you basically have to deep clone state before creating new state.
I think it's worth a try, but you can always move a few reducers at a time to using immutable instead of migrating your entire app. That way you can profile performance impacts and see if it's worth it to migrate the entire app.
My own personal opinion is that use of Immutable.js is mostly overrated for most situations. I wrote an extended comment on Reddit describing my concerns, at (Dan Abramov: Redux is not an architecture or design pattern, it is just a library). I'll paste the TL;DR: here:
Overall, my impression is that the performance benefits are overrated, it's too easy to make mistakes in usage that are actually a net performance negative, and you either have to go all-in on the API everywhere in your codebase or be very sure you know when you're using Immutable types vs plain JS and do conversions all over the place.
So yes, you generally either have to use toJS(), or explicitly call state.getIn() to extract pieces of data.
My React/Redux links list has a section on React performance, which includes several articles regarding Immutable.js performance (including some pitfalls, like overuse of toJS()) : react-redux-links.
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 .
so I have recently playing with React and the Flux architecture.
Let's say there are 2 Stores A and B. A has a dependecy on B, because it needs some value from B. So everytime the dispatcher dispatches an action, first B.MethodOfB gets executed, then A.MethodOfA.
I am wondering what are the advantages of this architecture over registering A as a listener of B and just executing the A.MethodOfA everytime B emits a change event?
Btw: Think about a Flux implementation without the "switch case" of the example dispatcher from facebook!
The problem with an evented approach is that you don't have a guarantee as to which handlers will handle a given event first. So in a very large, complex app, this can turn into a tangled web where you're not really sure what is happening when, which makes dependency management between stores very difficult.
The benefits of the callback-based dispatcher are twofold: the order in which stores update themselves is declared in the stores that need this ordering, and it is also guaranteed to work exactly as intended. And this is one of the primary purposes of Flux -- getting the state of an app to be predictable, consistent and stable.
In a very small app that is guaranteed to not grow or change over time, I can't argue with what you are suggesting. But small apps have a tendency to grow into large ones, eventually. This often happens before anyone realizes it's happening.
There are certainly other approaches to Flux. Quite a few different implementations have been created and they have different approaches to this problem. However, I'm not sure which of these experiments scale well. On the other hand, the dispatcher in Facebook's Flux repo and the approach described in the documentation has scaled to truly gigantic applications and is quite battle tested.
In my opinion I think this dispatcher is somehow an anti-pattern.
In distributed architectures based on event sourcing OR CQRS, autonomous components do not have to depend on each others as they share a same event log.
It's not because you are on the same host (the browser/mobile device) that you can't apply these concepts. However having autonomous stores (no store dependencies) means that 2 stores on the same browser will probably have duplicate data as the same data may be needed by 2 different stores. This is a cost to pay but I think in the long term it has benefits as it removes the store dependencies. This means that you can refactor one store entirely without any impact on components that do not use that store.
In my case, I use such a pattern and create some kind of autonomous widgets. An autonomous widget is:
A store that listen to an event stream
A component
A LESS file (maybe useless now because of React Styles?)
The advantage of this is that if there is a bug on a given widget, the bug almost never involve any other file than the 3 mentionned above ;)
The drawback is that stores that host the same data must also maintain it. On some events, many stores may have to do the same action on their local data.
I think this approach scales better to larger projects.
See my insights here: Om but in javascript