I have a component (table) that contains many lines with data editing in them, with masks in the form of contenteditable, it is possible to select all fields and change all the lines at the same time.
On desktop it works pretty fast, but on iPhone 6 I have unreal lagging, with Safari hanging for 20 seconds for each action.
I completed the recommendations to improve performance from React: prevent reconciliation, pure components, etc ...
Are there ways to improve performance? Is it necessary for me to ponder a functionality change on a mobile device, in favor of performance?
You should override shouldComponentUpdate component life cycle method for every row of the table. Ideally for every cell in every row.
If you have a table and it gets a different props. What happens is that every nested component gets re-rendered. PureComponents might help but writing shouldComponentUpdate is the only way to really control when something gets re-rendered.
Also for really large data list there is a react-virtualized. Check it out. Its pretty cool.
It would be nice if you could post source code though.
Adding to above answer, you should use react-perf module to exactly validate if any change actually made a performance gain.
https://github.com/crysislinux/chrome-react-perf
use this extension to exactly see how many times, each component on your page actually rendered, when you did your problematic/slow user interaction
try reducing no. of renders of each component. Also reduce the no. of components rendering on each such interaction.
try minimising time taken by each component. You can sort by time and focus on the most expensive components. Avoid rendering components higher in heirarchy, first. To find the exact reason behind a component's rendering use following method.
Put componentWillUpdate lifecycle hook, temporarily, and diff previous and next props/states. With this you would get the exact prop culprit behind a rendering. Unneccessary prop change might be in following scenarios:
When prop is just a function which is changing because of 'bind' usage or arrow-function usage, which changes the function reference everytime, and with that, causing new renders, everytime.
There might be a prop being initialised with new Object() or {} notation, which is considered new object everytime and hence new rendering. This can be avoided by a const READ_ONLY_OBJECT = {} and using READ_ONLY_OBJECT everytime a variable needs initialization.
You might be unnecessarily mutating object-type props and doing diffs in componentWillRecieveProps.
There can be more reasons to where we dont want a render but it happens because of the ways react works. Just see that props dont change unnecessarily. Also, dont put unnecssary componentWillRecieveProps/shouldCompoentUpdate checks as it can impact performance negatively. Also when using these, use these as higher in heirarchy as possible.
Some techniques to use
try to avoid using react lifecycle hooks which run on each render.
try reducing any scripts runing on every render.
use componentWillReieveProps, but only if you gain, else point 1 can reduce gains also. Also, using this often can lead to non-maintainable code. Always validate the gains with react-perf tools, before making changes related to optimizations.
use throttling in chrome-dev-tools to create slow device enviroments, use javascript profiling to see which javascript methods took most time.
Try using redux with react, to manage state. Redux also has componentWillReieveProps thing implemented for connected components. So, using redux will help.
When using redux use an appropriate batching stategy. You can also use batch middleware in redux.
Also, similarly, in react try to do events in batched manner so as to reduce amount of time spent in react's renderings and diffing algorithms. Try clubing setStates in react or actions in redux to reduce react scripting time.
Always use appropriate throttling/debouncing techniques while implementing input controls, to get immediate response. You can also use uncontrolled components to have immediate response, if your business logic allows. Idea is to not to run any javascript when user is typing or interacting with your page in any way, else he would notice the jank in devices particularly bad in computing power.
Your action handlers should not be lengthy. If lengthy, try to do them in chunks, asynchronously, with redux-actions or with just promises.
There is more to this list, but the problem is, react as a framewaork is pretty easy to get to work, initially, but sooner or later, any medium sized react app will run into these performance problems, as react's diffing and rendering logic incurs a lot of performance penalties in bad devices, as soon as app grows in size, only option is to get react-performance tools, also, into the build process, asap. This will let you validate and measure your improvements.
Related
I'm working on a Nextjs project with RTK Query. Can someone tell me how to access the isLoading state of the mutation that is initiated like this https://redux-toolkit.js.org/rtk-query/api/created-api/endpoints#initiate. I don't want to use the generated hook useLoginMutation but instead get the data by unwrapping the returned result after dispatching like this await dispatch(api.endpoints.login.initiate()).unwrap() because I don't want my form to re render. Thank you in advance!
because I don't want my form to re render.
Hi, RTK Query author here.
Generally, you can use the selectFromResult option to reduce the amount of fields returned from the hook, and as such also reduce the amount of rerenders (as less things are changing).
Generally though, I have to strongly advise you: don't care about the amount of rerenders on this level. React is made to fastly rerender your components. One, two, or even five rerenders within a 1-3 seconds frame should not make any difference for your application - usually, your component will rerender on every keypress in your form anyways!
If, and only if you are seeing actual performance degradation, you get to the point of optimizing things like this - and then you would see if somewhere you have dozens or hundreds of rerenders, but still do not care about single-digit rerender numbers. If single-digit rerenders are a problem for you, you have heavy computation logic inside your components, and you need to optimize that - the execution of one of your component functions should always be in the sub-milliseconds. Then that's the place to optimize.
As for triggering the mutation with initiate: It will be loading until your await continues and done after that. If you just need that information, there is no need to access an isLoading state. You must set the component state if you need that information in your component. And that would trigger a rerender. You see where I am going: use the hooks! That's what they are made for.
Also, if using initiate: make sure to unsubscribe the result afterward or it will stay in cache forever. Again, this is something the hooks do for you.
I am currently upgrading react version from 16 to 17, and refactoring old code (changing class-components to functional components, use hooks, get rid of mobx).
There is currently a pattern in place, which I am not sure about:
Whenever there is a user-interaction, the respective state-change is done, by
Calling the Setter-Function of React.useState
Cloning the whole state-object with _.cloneDeep
Applying all the changes on the cloned-state-object
Returning the cloned-state-object
This pattern is nice, because within the Setter-Function of react, I can do as many state-updates I want; I even can pass this state-object to other functions (within the react-setter-function) which then apply additional state-updates if necessary;
I've not yet discovered any performance problems with that pattern, but I suspect, that I trigger a re-render of the whole page, whenever I replace the state-object with that cloned-object.
Should I change the pattern or stick to it?
I'm currently working on a single page dapp for lucky bunny farm, it all works and will be released soon. But i'm wondering if maybe i've engineered it entirely wrong because i have put most of the business logic within a collection of useEffects (6). Because i dont have any other pages on the site i've not created hooks as i would in other situations because there's no benefit from a writing code point of view.
It seems to me that having 6 useEffects working off the state variables i've set might be a little much, is there a performance gain from reducing them or doing something else? I have created components for the various on page assets and those internally have their own state and useEffect hooks too. What's the danger in a "large" number of these hooks and at what point should i consider optimising for performance.
Or am i over thinking this and actually this is quite normal and i should only worry when i have say 20 hooks all doing their own thing.
Additionally, i tend to use state for single variables instead of objects, is there a performance gain from using a single state with an object.
So to use an example i have the following states:
dappActionStarted
dappActionCompleted
dappActionError
Would it be more efficient to have something like:
{
started
completed
error
}
And then do a single useEffect for that object as opposed to the three i would need to manage 3 seperate state vars.
These past few days, i've been playing around with different animation libraries for React, in an effort to find a solution for transitioning between views (not routes), where a view would be a component wrapping other components and so on.
so far i tried:
react-transtition-group
react-animations
react-spring
Still need to experiment with react-motion's Transition...
...and there are a lot more out there, but all these, do what i need, except for one thing... while each state of the transition/style is applied, the child component(s) always update, triggering a re-render (which makes sense by the way), unless the child's shouldComponentUpdate() returns false, or is wrapped inside a PureComponent, both of which are not a solution, since you might (surely) want to do "things" with your component after the transition ends.
All the examples out there, serve their purpose, but they all use either functional components, or simple strings, for demo purposes, none of which one should care if are re-rendered or not, but a simple modification that would log every time the component is rendered, will show that they render multiple times during the transition.
Oddly enough, nobody seems to care, or is unaware. I have found very few questions or issues regarding this matter, though it's very much real, and the libs are very poorly documented on this.
Please share your solutions for avoiding this issue.
My workaround is to wrap the transitioned children/views inside a simple PureComponent, to prevent them from re-rendering, still it doesn't seem right.
I read about React being very fast. Recently, I wrote an app to test react against angular. Unfortunately I found react performing slower than angular.
http://shojib.github.io/ngJS/#/speedtest/react/1
Here is the source code for react. I'm very new to react. I am sure I'm doing something wrong with my react code here. I find it unusually slow.
https://jsbin.com/viviva/edit?js,output
See if any react experts can find the bottlenecks.
Update 1:
Removed the usage of context.
Better usage of setState.
Better usage of shouldComponentUpdate.
I still can't make it faster than angular or even close to it.
https://jsbin.com/viviva/96/edit?js,output
Update 2:
I made a big mistake by creating 2d arrays in the cell component. So I moved them to a mixin. Now I believe that react is faster than angular in DOM manipulations.
https://jsbin.com/nacebog/edit?html,js,output
Update 3:
My mistake again. I did it wrong which made it faster. After analysis, it was rendering incorrectly. If anyone can help me understand, if this could be any faster. I know react is not good at dealing large arrays. In this scenario, it's dealing with four 3d arrays. https://jsbin.com/viviva/100/edit?html,css,js
React's performance is exaggerated. It's fast enough for most real use cases. Rendering large lists is its main weakness.
Also this always returns true (unless the update is triggered by setState). You need to shallow compare the props.
shouldComponentUpdate: function(nextProps, nextState) {
return this.props !== nextProps;
}
And you should be using props in the places you're using context.
This is a very contrived example in my opinion.
As stated above, you are using context incorrectly.
There is no need for a mixin: the number of columns and rows can and should be passed down as props. create2DArray, getRandomNumber should be declared at the top of your script as simple global functions.
You are setting the state incorrectly. You should never change the state like this this.state.some = 'whatever', you have to use setState
this.setState({ some: 'whatever' });
You're using context incorrectly, the documentation states:
In particular, think twice before using it to "save typing" and using
it instead of passing explicit props.
It's mostly beneficial for passing context objects like currently logged in user or perhaps a redux store. Your app is using context when it should be using props.
You'll need to ensure that shouldComponentUpdate is a meaningful predicate. See https://facebook.github.io/react/docs/advanced-performance.html
If you correct those two things it'll be a better measure of React's performance compared to Angular. At the moment you've got a well tuned Ferrari running against a model T Ford (held together with chewing gum).