React is fast, but not always fastest among other cases like Vue/Angular. It depends on the use case. In generally I can say React is fast because of it's Virtual DOM. It renders everything in JavaScript and then changes only the things changed in the actual DOM.
DOM is very slow and changing it costs lots of processing time of the browser. But in this case javaScript is super fast since it uses V8 engine to handle execution inside the web browser. (V8 engine is the backbone of Google Chrome and other chromium based web browsers)
To get real benifits of React ecosystem you should follow standards and procedures according to their documentation. Other than the official guide there are many ways to speed up your react application. Let's dig into the topic.
Performance Tweaks
- Designing Project Structure
- Maintaining Immutability
- Functional Components
- Dependancy Optimization
- Avoiding Inline Functions Inside Render Function
- Props Validations
- Handling Animations
Designing Project Structure
When i started web development, I had no idea about what are the design patterns or file structures to follow in front end. So in my first two projects, just followed the documentations to build the websites. But later on I realized this is not the way to build a application with proper standards and better performance.
Atomic Design Principle
With large single page apps(SPA), we need to create hundreds of components to achive the requirements. In that case, if we are defining each component with common elements re-usability will go down to zero quickly. In Atomic design conept there are multiple levels of blocks,
- Atoms
- Molecules
- Organisms
- Templates
- Pages
Here these components works as building blocks of the DOM. Above all components concurrently working together to create effective interface design systems. Atoms are the smallest elements in the hierarchy(eg: Text inputs, Buttons, Texts). Combination of Atoms becomes Molecules(eg: Text input with title and the button). Then combining Molecules we build organisms(eg: Header, Footer, Side Menu). After all we create templates with organisms and wrap pages with templates.
Benifits of Atomic Design
- Components can be developed seperately(working as a team is easy)
- Testing becomes very easy due to component based testing
- Styling becomes easy, cause of high re-usability and customizable due to component target CSS
- Reduce import cost of dependancies(Reduce bundle size)
Maintaining Immutability
When we are thinking functional programming way, Immutability takes important place in functional programming. It's a concept that React programmers need to understand.
Immutability means that something cannot change once it is defined. Immutable variables/objects are simpler to create, test and can use with zero side-effects. Let's see some examples.
addNews = () => {
const news = this.state.news; // let's assume this is an array
// highlight-start
news.push({
id: "dsd87a68as7d6987d8a9d79as",
title: "Space X successfully lands rocket",
});
// highlight-end
this.setState({news: news});
}
Here we are pushing new item to news
array and it refers to this.state.news
In this case it won't re render the component because of the same reference.
To overcome this issue we have to avoid mutating state as follows.
addNews = () => {
this.setState(state = > ({
news: state.news.concat({
id: "dsd87a68as7d6987d8a9d79as",
title: "Space X successfully lands rocket",
})
}));
}
You can use Array.concat()
higher order function to avoid mutating state or, samething you can do with spread operator in ES6.
addNews = () => {
this.setState({
news: [...this.state.news, {
id: "dsd87a68as7d6987d8a9d79as",
title: "Space X successfully lands rocket",
}],
});
}
Functional Components
Earlier we also called functional components as stateless components. Because unlike class components we couldn't able to manage state in functional components. But in later React introduced Hooks in React v16.8. With Hooks we can manage state and use lifecycle methods in functional components.
Functional components prevent constructing class instances while reducing the bundle size as it minifies better than classes.
Following snipt shows example for basic Hooks. You can read more about Hooks from the official doc.
import React from 'react';
const initialState={
count: 0,
};
const SampleComponent = () => {
const [state, setState] = React.useState(initialState);
React.useEffect(() => {
// This will work as component did mount
const subcription = props.subscribe();
// Return act as component will unmount
return () => {
subcription.unsubscribe();
}
},[]);
}
export default SampleComponent;
Dependancy Optimization
When we are using thirdparty libraries, if we forget to check on import cost of those, It will cause an increase of overall bundle size of the application.
As a example, let's say you are using meterial-ui package for your application. When you are importing material-ui components, you can minimize your import cost by importing individual modules.
import React from 'react';
// Should follow this
import Button from '@material-ui/core/Button';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
// Should avoid importing core modules
import {Button, Menu, MenuItem} from '@material-ui/core';
In above code, we should import components module wise. If we import core module instead component wise, It will load un-used components as well. This will definietly increase the bundle size.
Also if you are following Atomic design pattern then you will only import modules at Atomic level. It will cause to reduce bundle size because of re-usability.
Avoiding Inline Functions Inside Render Function
Functions act as objects in javaScript. In this case if you are defining inline funtions inside JSX elements, It will re-render and create new instances every time when React does it's prop diff check. Like wise we should avoid below practice.
import React from 'react';
const SampleComponent = (props) => {
render (
<button
onClick={() => {
props.navigate('/somewhere');
}}
>
{'Click here'}
</button>
);
}
export default SampleComponent;
Instead of we can do it as follows, It will avoid creating new instances and reduce work of the garbage collector.
import React from 'react';
const SampleComponent = (props) => {
// highlight-next-line
const navigate = () => props.navigate('/somewhere');
render (
<button
onClick={navigate}
>
{'Click here'}
</button>
);
}
export default SampleComponent;
Props Validations
Same as the state we never mutate prop values. They have removed PropTypes since React v15.5, So if you want to use PropTypes you have to install it separately By the way it's always better to handle prop validations in your application.
If you are using class components, avoid initializing props in constructor. Because constructor runs only one time. Props changes won't effect in the component if you do that on constructor.
Instead you can use props directly or create const
inside render function and get the reference of the props.
Handling Animations
In React they have provided React animation guide in the documentation. When it comes to performance, for advance animations like, bouncing, reverse, rewind Its better to use Javascript(React) animations. For one time or small animations you can use CSS animations/transitions instead React animations.
Conclusion
As you can see there are many ways to optimize React applications. Other than above tweaks, webpack analyzing, lazy loading, sever side rendering(SSR), Service worker optimizations(Caching) and many more methods are there.
Best point to starting optimization is the initial stage of the project. When the project scope get increase, it becomes hard to manage the code base. This is a process, It should work from the initial stage.
If you know more about optimization, Please drop a comment below and share your experience 😉
Don't forget to checkout my personal blog : https://codewithsamiya.com/blog/optimize-performance-of-your-react-app/
Top comments (0)