Idiomatic way to cache computed values based on the state in React? - javascript

React documentation says
Don't worry about precomputing values based on state — it's easier to ensure that your UI is consistent if you do all computation within render().
http://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html
This makes perfectly sense when the computations are small.
But I'm storing the bunch of large arrays in this.state for data visualizations I'm rendering on SVG. I have to compute several values based on those. The thing is that those computations are fairly heavy and it is impossible to compute those always within render.
So, how should I go about caching those computations while ensuring that I don't get inconsistent state with this.state and those computed variables?

I think I've figured it out.
I moved the large arrays to the state of the parent component and I'll just pass them as props to the visualization component. Then I just compute the values in componentDidMount and componentWillReceiveProps and save them into the state of the visualization component.
This avoids most of the useless computing in my case. But if it is not enough I can go further and diff the current props with the next props in componentWillReceiveProps to determine if the computation is actually needed.
UPDATE: Now that I've worked more with React I think this should be done using memoizing. Reselect is good lib for that.

I tried some data visualization with React and SVG as well, and did not have any performance problem yet. React only rerender on state change, or parent component's state change so those computations are not run very often.
If in your case the components are updating frequently, you can try memoize the computing functions with lodash.

Related

Does redux evaluate all listeners to the store on any update to the store?

From what I can tell, redux will notify all subscribers to the store when anything in the store changes no matter if it's a subscription to a deeply nested leaf or a subscription to the top level of the state.
In an application where you follow the guiding principle:
many individual components should be connected to the store instead of just a few... [docs]
You could end up with lots of listeners and potentially performance issues?
Disclaimer: I understand that the selector functions will only cause a re-render if the result of the selector function changes. I understand that just because the listener function is evaluated, doesn't mean the subscribing component will re-render. I understand that evaluating a selector function is comparatively cheap to a react component rendering.
However, I just would like to confirm that this is indeed how redux works?
e.g. given the following example listener
const result = useSelector(state => state.a.b.c.d.e.f.g.h.i.j.k)
if we update some other value down some other path, not relevant to the above listener e.g.
const exampleReducer = (state) => {
return { ...state, asdf: 'asdf' }
}
From my understanding, all listeners, including the example above, will be invoked.
For context, my actual use case is I'm using https://easy-peasy.now.sh/ which is built on redux. To be clear, I don't have any current performance issues in production related to binding too many listeners. However, each time I attach a listener via the useStoreState hook, I'm wondering whether I should minimize binding yet another listener to the store.
Also if you're curious, inspired by this thinking, I implemented a state tree which only notifies the relevant listeners.
Perhaps this is a premature optimization for a state library... but if so why? Is there an assumption that applications using redux will have simple and fast selectors and that the application bottleneck will be elsewhere?
I'm a Redux maintainer and author of React-Redux v7. The other couple answers are actually pretty good, but I wanted to provide some additional info.
Yes, the Redux store will always run all store.subscribe() listener callbacks after every dispatched action. However, that does not mean that all React components will re-render. Per your useSelector(state => state.a.b.c.d) example, useSelector will compare the current selector result with the previous selector result, and only force this component to re-render if the value has changed.
There's multiple reasons why we suggest to "connect more components to read from Redux":
Each component will be reading a smaller scoped value from the Redux store, because there's less overall data that it cares about
This means that fewer components will be forced to re-render after a given action because there's less of a chance that this specific piece of data was actually updated
Conversely, it means that you don't have cases where one large parent component is reading many values at once, is always forced to re-render, and thus always causes all of its children to re-render as well.
So, it's not the number of listener callbacks that's really the issue - it's how much work those listener callbacks do, and how many React components are forced to re-render as a result. Overall, our performance tests have shown that having more listeners reading less individual data results in fewer React components being re-rendered, and the cost of more listeners is noticeably less than the cost of more React components rendering.
For more info, you should read my posts on how both React and React-Redux work, which these topics in extensive detail:
A (Mostly) Complete Guide to React Rendering Behavior
The History and Implementation of React-Redux
ReactNext 2019: A Deep Dive into React-Redux
You may also want to read the Github issue that discussed the development of React-Redux v7, where we dropped the attempt to use React Context for state propagation in v6 because it wasn't sufficiently performant enough, and returned to using direct store subscriptions in components in v7.
But yes, you're worrying too much about performance ahead of time. There's a lot of nuances to how both React and React-Redux behave. You should actually benchmark your own app in a production setting to see if you actually have any meaningful performance issues, then optimize that as appropriate.
From what I can tell, redux will notify all subscribers to the store when anything in the store changes no matter if it's a subscription to a deeply nested leaf or a subscription to the top level of the state.
Yes, all subscribers are notified. But notice the difference between Redux and its React-Redux utils.
You could end up with lots of listeners and potentially performance issues?
With React-Redux you subscribe to a store (of Redux) by having a selector (useSelector/connect).
By default, every subscribed component in React-Redux will be rerendered if its subscribed store portion changed, to handle it you pass a selector which bailout the renders.
But for Redux:
The notification itself handled by Redux (outside React).
Redux doesn't handle the "deeply nested leaf" (React Context API handles it as part of React-Redux implementation) it doesn't handle locations - it just calling callbacks.
The notifications are batched in a while loop outside the React context (optimized).
// There is a single Subscription instance per store
// Code inside Subscription.js
notify() {
batch(() => {
let listener = first
while (listener) {
listener.callback()
listener = listener.next
}
})
}
In conclusion, if it's not a case of premature optimization:
Premature optimization is spending a lot of time on something that you
may not actually need. “Premature optimization is the root of all
evil” is a famous saying among software developers.
All subscribers in Redux will be notified, but it's not influencing the UI.
All subscribed components will be rerendered only if the portion of the state changed (enhanced with selectors) - influencing the UI, therefore thinking about optimizations, you should subscribe to comparable portions of the store.
I assume you are talking about react components that get state from redux (tags in your question) using react-redux. The react-redux tag is missing but that is what is mostly used and used in the standard create react app template.
You can use the useSelector hook or mapStateToProps with connect. Both more or less work the same way.
If an action causes a new state to be created then all functions passed to useSelector or mapStateToProps will be executed and the component will be re rendered only when they return a value that is not referentially the same as previous value. For mapStateToProps it works a little different as it does a shallow equal comparison with the value returned.
You can use reselect to compose selectors and re use logic to get certain branches and/or adapt the returned data from the state and to memoize the adapted data so jsx is not needlessly created.
Note that when a component re creates jsx that does not mean the DOM is re created since React will do a virtual DOM compare of the current jsx with the last one but you can optimize by not re creating jsx at all with memoized selectors (using reselect) and having pure components.
The worst thing you can do is pass a handler function that is re created on every render since that will cause jsx to be re created because props changed and DOM to be re created since the handler function causes virtual DOM compare to fail, for example this:
{people.map((person) => (
<Person
key={person.id}
onClick={() => someAction(person.id)}
person={person}
/>
))}
You could prevent this from happening using the useCallback hook from React or create a PersonContainer that will create the callback () => someAction(person.id) only when re rendered.
This is not exactly answer to the original question BUT related enough to be mentioned.
Sometimes on very complicated React systems Redux notifications may actually cause trouble. If every other optimization technique seems exhausted you might want to hack Redux itself a little bit.
See:
https://www.npmjs.com/search?q=redux-notification-enhancer
This enhancer allows to reduce amount of renders in React by reducing notifications coming from Redux. It can be achieved by enabling throttling and/or marking certain actions as passive (updating state but not causing render). Both optimization techniques will increase complexity along with performance - use with care.

Isn't React's immutable element creation and rendering mechanism terribly inefficient?

I am not a React developer, but I am implementing a similar State and Props management infrastructure in another language. While reading about React's state management and rendering mechanism, I came across this quote
React elements are immutable. Once you create an element, you can’t change its children or attributes. An element is like a single frame in a movie: it represents the UI at a certain point in time.
If I understand correctly, every time the parent component's state changes, its children's render methods are called (if their Props was affected) and these child components are recreated and (re)rendered.
Isn't this terribly inefficient, especially if the child components involve complex computations, visualizations, etc? Is there a mechanism in React to create the components once, but update (not recreate) only the necessary parts as the states change?
Well, that's the whole point of why we use React.
Have you heard about Virtual DOM? Virtual DOM is simply a memory instance that saves the exact replica of the real DOM.
When there is a prop/state update, it does not re-render the whole thing, but only re-renders the UI parts that are affected.
So, it's very efficient and to see how they do it, you can check the source code here.

How does the state updates of objects in React work accurately

I am learning React, and trying to wrap my head around the syntax, and concepts. From the tutorials of React it is mentioned:
State Updates May Be Asynchronous
React may batch multiple setState() calls into a single update for
performance.
Because this.props and this.state may be updated asynchronously, you
should not rely on their values for calculating the next state.
My question is, if the this.state is not updated at all times, can we rely on it to show the right information? If my understanding is correct, React will update this state in batches for performance reasons, but does it affect the accuracy of the application? How does React create these batches and when do they get applied?
React uses state to help manage each piece of component with javascript. Since state can always change it makes it really flexible. One downside is that since it is flexible it can be hard to manage the state when there are multiple objects. It is ideal to keep components in manageable pieces so that you can locate when a state is not behaving as expected.
To prevent data from mutating unexpectedly, tools/concept such as ImmutableJs or Redux have been combined with React to make managing tools more efficent.
Redux controls/organizes where pieces of state changes through a one-directional flow. http://redux.js.org/docs/basics/UsageWithReact.html
ImmutableJs uses persistent immutable data structures which locks state to prevent unexpected changes. https://facebook.github.io/immutable-js/
React will render component with updated state as soon as it is reasonable - for example in event handlers you are able to change state of multiple components, however it is not reasonable to render them with new state separately - instead React will batch updates and render components after event handler finishes.
In correctly written application delay between update and render will be unnoticeable for user. From developer perspective asynchronous updates may introduce hard-to-find bugs (using Redux where every state update is based on previous state should solve most of them; this is of course possible also in pure React by using setState() with callback).
State being asynchronous does not mean that you can't rely on it, but you should be careful how and when you are using the information you are keeping there.
For example:
this.setState({charCount: 5});
console.log(this.state.charCount) // may not be 5 as setState is asynchronous
On the other hand you can use callback to be sure that you got a correct value:
this.setState({charCount: 5}, () => { console.log(this.state.charCount) });
General practice is that you should try to minimize the use of state and only use it, when changes are needed on user interface. If you need to process or manipulate data without UI changes try to avoid using state and use for example this practice: Lifting State Up

react setState() update all components in browser

I'm having a huge form built with react and material-ui. The form uses two way binding and update state for input changes. changing any input filed cause all components to update (obvious by react developer tools TraceReactUpdate enabled). When it comes to TextField it makes my page rendering very slow. using this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this) doesn't help.
It can be extremely difficult to find issues like the above, because it totally depends on the actual code you have written. I am sure that the react rendering concept works (as it has for myself and so many others), but without seeing more code it is impossible to pinpoint the actual problem.
Still, I have a feeling that the real cause is "simple", meaning that it is very likely due to a prop being passed that has indeed changed. Maybe not in value, but in instance. IIRC, the PurerenderMixin is not comparing values (unless the data are value types), it is comparing instances. So even if the data is the same, if the instance has changed then it will re-render.
Some key-points to consider:
Are you passing just the props that you need to each component, or are you passing all props to them all?
Are the data-structures immutable?
Are you sure that you are not passing data that changes on the iterations, like passing the javascript [] as a prop will mean that the data has changed (see https://medium.com/#esamatti/react-js-pure-render-performance-anti-pattern-fb88c101332f#.hx97qk4tx for sample on how this can screw up your day).
If you explicitly create a shouldComponentUpdate() method for the components then you can control this yourself. The PureRenderMixin does a shallow check to see if the props have changed, but, if you are passing them all then no matter if they have been used or not in the render method then just one of them changing will mean that the component is considered to need to render (as in, not mount, but render in memory and reconcile possible changes with the dom). Using shouldComponentUpdate can help stop rendering based on your own checks.
Using immutable props can also be helpful. The React PureRenderMixin only does a shallow comparison, as mentioned. So, if you are passing data-structures in the props that have depth (like sub-properties), then these are not checked. Meaning that you could end up with the opposite problem you have now, that is components that should have updated but aren't. If you are using i.e. redux and have done "the right thing" and are using i.e. Immutable.js, then using the PureRenderMixin is good enough.
Reading the specific docs for this may or may not help. There's some good description of this in the React manuals: https://facebook.github.io/react/docs/advanced-performance.html#shouldcomponentupdate-in-action
And - I forgot to say, if you are using redux then you could consider these somewhat elegant and simple ways of handling your forms:
http://redux-form.com/
https://davidkpiano.github.io/react-redux-form/
Hope that this helps. Good luck.

ReactJS: PureRenderMixin addon footnote - contradiction?

from the documentation here: http://facebook.github.io/react/docs/pure-render-mixin.html
The footnote is saying that you should use forceUpdate() if the structure of complexe data (deep data structure) is changed.
From the definition of a pure : it renders the same result given the same props and state.
I'm thinking more and more that this is a contradiction because if the data structure changes, it means that you are giving new props/state. Thus the component is not "pure" anymore.
In my opinion, if you change the props or state that is passed to the component you can either:
use forceUpdate().
remove PureRenderMixin from the mixins.
Thus, under the hood... you are transforming a component that is pure to a "non-pure" component. So removing PureRenderMixin should be the only option available.
Am I right ? Or a Pure component means that the component is "cached" and reused when giving the same props ?
Sorry but I'm a bit confused here.
PureRenderMixin is used to give React a way of knowing that it shouldn't call your render method unnecessarily. For example, if your render method is complex enough, it can give you a performance boost if your component isn't being re-rendered with the same props/state.
But, like it's said in the documentation, PureRenderMixin does not compare deeply nested data structures, so it might not call your render function, when it should have, because some nested structure actually changed.
In these cases, it's better to not use PureRenderMixin and use shouldComponentUpdate and perform you own comparison logic.
Also, from the docs, you should avoid using forceUpdate.
The absence of side effect is an important aspect of the mixin because it enables the logic of not rendering the component twice given the same state.
That shouldn't be a satisfying answer because, as you pointed out, nested changes won't be caught by the shallow checking... Unless your data structure are immutable!
I strongly recommend watching Lee Byron's talk on immutable data structures which explains how immutable data improves the performance of your application by avoiding a whole class of problems.
Essentially, a smart library like immutable.js will share common state between two snapshots of an immutable object.
Therefore shallow equality becomes a proof of the underlying data not being changed.

Categories