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
Related
I am using redux to manage a global state and sagas for async server calls in a react native app.
Can it improve the performance / minimize rendering to split the calls to redux state when connecting a component to the redux store?
E.g. a big object in the redux store is composed of many smaller ones.
{bigObject : {small1, small2, small3....}}
in mapStateToProps for a class, is it more efficient to make separate calls to each of the smaller objects that are required (small1: state.bigObject.small1), or is it better to have only one call to the larger object ( big: state.bigObject)?
Similarly, can it be good practice to create local state copies of the redux state (e.g. setState for class) or is it better to call the redux state directly in the component (e.g. this.props.state.bigObject.small1) anywhere it is needed? Does it have an impact?
Thanks a lot!
No. Once your state is in memory, it's in memory. Redux is just a fancy object, and object access is in O(1) time. All you would be doing is taking up additional memory and and processing time by duplicating your state. Not to mention the likelihood of bugs from local and global state getting out of sync.
Redux and React are already optimized to solve this problem. Here's a section of the React docs that covers this.
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.
I am somewhat new to ReactJS.
I want to store data for complicated computations in ReactJS. Since the setState is asynchronous, I cannot be bothered to store all the required data inside state as it would be next to impossible to do what I want.
I was thinking of doing the following: store the needed variables inside an object inside the state itself. E.g the state defined in the constructor is the following object
constructor(props){
this.state = { complicated_storage: { x : 123, y : 324 } }
}
This way I can manipulate this.state.compicated_storage.x or this.state.compicated_storage.y, and do stuff like this.state.compicated_storage.x = 4 without worrying about asynchronous behavior.
Is this a bad way of doing stuff in ReactJS. I noticed that with this you can bypass the entire setState mechanism, and just store all my variables inside the object within the state.
Thank You
Is this a bad way of doing stuff in ReactJS. I noticed that with this you can bypass the entire setState mechanism, and just store all my variables inside the object within the state.
The entire purpose of state is re-rendering components whenever it changes. If you modify it directly, such as state.someVariable = 2, React will not know about your change, and it will not rerender your components after the change (however, the change will be reflected if something else later causes a rerender).
If you need a change to some data trigger a rerender and update the view, use state together with setState.
If not, you can simply use a class field, rather than store it inside state.
Besides, I'm not sure in what way asynchrony you think will impede your goals, so perhaps you should be clearer there. State being asynchronous just means that changes to state are made "a little later" after the function is called (it's a whole other topic), so React can batch updates for performance reasons.
Last but not least, you should look into hooks (useState), instead of using class components.
I'm working on a react web app and our company bought an admin dashboard panel to save time. In this panel, they used redux to handle states and all setting parameters stored into redux ...
But really I'm confused about using Redux for each use case!
All of my requests and states are components base and are not global and those are not essential to use in other components of this app!
For example to load games list I've this code :
componentDidMount() {
this.setState({
loading: true
});
http._GET('/game/getAllGames')
.then(response => {
this.setState({
loading: false
});
this.props.dispatch(gamesListAction(response.data.result.games));
});
}
In this case, I use a response and list only on the games-list page. So I think it's not logical I store a response.data into redux and then get all data with connecting and another process...
Or another example, for inserting forms I'll never need to store forms insert or API response because it's inserted and not getting data from API!
I've read about redux but I think redux is not suitable for every app and use case and I should not store single-use responses to redux.
The reduxjs FAQ describes it the best.
In general, use Redux when you have reasonable amounts of data changing over time, you need a single source of truth, and you find that approaches like keeping everything in a top-level React component's state are no longer sufficient.
Redux is nothing but a state mangement tool and you need more compelling reasons to use it:
In your case, firstly:
React's setState will bloat the component overtime with growing requirements and it is much
harder to maintain. Separating out the state management into a reducer
refactors nicely and makes it more readable.
Caching component state, for example if you are using a shopping cart, progressive wizards. There a is lot of to and fro in user interaction which result in state changes, in such cases. Maintaining your state in redux makes a lot of sense now.
Deeply nested components passing on state and lots of props to their children quickly bloat with growing requirements. This is a classic scenario with lot of wrapper components (especially with UI details). A better way would be to refactor and directly connect low level components to redux (transform into a container. Read: presentational-and-container-components)
Application state mapping to multiple container components. For example, if you had your getAllGames loading state to be represented in some progressive-loader-component somewhere out in your app. Using redux will ease your pain sharing data between this components.
Useful when building root level components which can possibly have interactions from everywhere. Like your useraccount component, modal, alerts, loaders.
You will realize, you are writing some boilerplate code with actions and reducers. Though overtime this is much better than reacts state management which can progressively grow complex within stateful components quickly.
Yes, You are right redux is not suitable for every application, as per my knowledge redux or state management is used mainly if you want to show the user previous state instead of empty when some operation is happening
Here is a bit detailed explanation about when to use redux
https://medium.com/#fastphrase/when-to-use-redux-f0aa70b5b1e2
Happy Coding !
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.