The React Best Practices That Will Make You a Better Developer

Prince Verma
OneAssist Tech
Published in
6 min readMay 24, 2023

React is a powerful JavaScript library for building user interfaces. It is declarative, efficient, and flexible, making it a popular choice for building large and complex applications.

However, React can be a complex library to learn. This is why it is important to follow best practices when writing React code, to make it efficient, maintainable, and scalable.

There are majorly four things that we look at when developing an application, especially in React, namely: Performance Enhancement, Code Quality, Initial Load Time, and Reduced chances of errors and inconsistencies. So the best practices discussed in this article are divided into these four topics that will ultimately guide you in writing clean code that enhances your application’s performance, decreases the chances of errors, and makes it easy to debug.

Let’s start with enhancing the performance of our React application.

1. Best Practices for Performance Enhancement of React Application: -

1.1 Use of React.Fragments to reduce the number of nodes: -

In React we know, that multiple components should be grouped and wrapped around a single ‘tag’, which is then returned as a component. Many developers wrap these multiple components around the ‘<div>’ tag/ component which is not advisable as it creates an extra node in the DOM.

React.Fragment is a component that allows you to group a list of components without adding extra nodes to the DOM. This reduces the number of HTML wrappers and enhances the performance by reducing the amount of DOM manipulation that React has to do.

It can be used in two ways as given below: -

  1. Using <React.Fragment>
  2. Using <>, </> (shorthand notation)

An example of using React.Fragment can be shown below: -

<React.Fragment>
<ChildOne />
<ChildTwo />
<ChildThree />
</React.Fragment>

or you can use the shorthand notation:

<>
<ChildOne />
<ChildTwo />
<ChildThree />
</>

1.2 Keeping the state of the component Local whenever possible

The performance of a React application can be optimized by reducing the number of props and states that need to be passed down the Component Tree. This requires us to maintain a local component state wherever possible and reduce the complexity of React application.

For instance, instead of depending on props passed down from a parent component, a toggle button component, may keep track of whether it is now in an on or off state using its local state as given in the following example: -

import React, { useState } from 'react';
function DemoComponent() {
const [count, setCount] = useState(0);

const handleIncrement = () => {
setCount(count + 1);
}

const handleDecrement = () => {
setCount(count - 1);
}

return (
<div>
<p>Count: {count}</p>
<button onClick={handleIncrement}>Increment</button>
<button onClick={handleDecrement}>Decrement</button>
</div>
);
}

export default DemoComponent

But, it is very important to keep in mind that, any update in the local state should be controlled, with proper validation and handling of errors, and the setState method must be preferably used to do so. This will ensure that the component remains in a consistent and predictable state.

Apart from performance, the way of writing our code also matters a lot. Writing clean code enhances our efficiency as well as code maintainability and consistency. So below are some of the best practices for writing clean code with reusable components.

2. Improving code quality with reusable components: -

A reusable component is a small piece of user interface that is used in several parts of an application, with each possibly having some customizations. Thus, making reusable components in React can be a great approach to make your code more scalable and maintainable. You can divide your app into more manageable chunks by designing reusable components. This makes it simpler to comprehend and change your code, as well as to reuse it across various components of your app. Above all, a reusable component reduces the unnecessary repetition of code in the application.

Below are some tips to maintain clean, reusable components: -

2.1 Passing data through props and using default props: -

As we know, props in React are used to pass data from the parent component to its children. Thus building a generic component in React, and changing its UI according to the props passed into it can be a good way to reuse the code without compromising its flexibility.

Additionally, you can add default props to the reusable component so that it works just fine even when you don’t pass the default props to the component.

An example of reusable text input field is as shown below: -

const TextInput = ({ handleChange, value, type, placeholder, label, id }) => {
const styles = {
marginTop: "4px",
padding: ".2rem .5rem",
border: ".2rem solid grey",
outline: "none",
borderRadius: "1rem",
};

return (
<>
{label && <label htmlFor={id}>{label}</label>}
<input
style={styles}
type={type}
placeholder={placeholder}
onChange={handleChange}
value={value}
id={id}
/>
</>
);
};

TextInput.defaultProps = {
placeholder: "Your Text Here",
type: "text",
};

export default TextInput;

So, from the above example, we can say that various TextInput components can be added to our React App having the same style but different labels, types, values, onChange functions, etc. Thus our reusable component can be customized based on props passed into it.

2.2 The Container/ Presentational pattern: -

Consider the case of fetching the data through API, applying complex logic to generate a list of data sets, and finally rendering them through lists. Here, it is thus advisable to separate the code into two different components, one to fetch data, and perform any complex logic (container component) and another to render the data set (presentational component). This pattern is known as Container/ Presentational pattern that separates logic (data fetch) from the UI code.

You can look at the below example that uses Container/ Presidential pattern to fetch the author data and then renders it, both functionalities being in different components.

In FetchComponent file: -

import React, { useState, useEffect } from "react";
import RenderComponent from "./PresentationalComponent";

const FetchComponent = () => {
const [author, setAuthor] = useState(null);

useEffect(() => {
const fetchAuthor = async () => {
const author = await fetch("https://medium.com/@princevermasrcc");
const authorData = await author.json();
setAuthor(authorData);
};
fetchAuthor();
}, []);

if (!author) {
return null;
}

const { first_name, last_name, bloglist, email} = author;

return (
<>
<RenderComponent
firstName={first_name}
lastName={last_name}
blogList={blogList}
email={email}
/>
</>
);
};

export default FetchComponent;

In RenderComponent: -

import React from "react";

const RenderComponent = ({
firstName,
lastName,
blogList,
email,
}) => {
return (
<div>
<h2>
Name: {firstName} {lastName}
</h2>
<p>{email}</p>
<p>{blogList}</p>
</div>
);
};

export default RenderComponent;

We can see from the above example that the task of fetching data and applying logic remains with FetchComponent, and the task of rendering with RenderComponent. This increases the readability of the code.

3. Some good ways to reduce initial load time:-

3.1 Loading components of a page asynchronously: -

The initial load time of the components can be reduced by splitting them into many chunks and loading them as and when needed. This is known as code splitting which allows the browser to only load the code that is needed rather than loading it all at once.

react-loadable library is one such example that can be used for code splitting.

3.2 Use of React Windowing and Lazy Loading: -

Consider the case of rendering large lists in your React App. This can take a lot of memory and computational power if the entire list is rendered at once. Don’t worry in this case, you’ve got React Windowing/ List Virtualization to the rescue…

React Windowing or List Virtualization is a method that renders only the items visible on the screen rather than loading the entire list. This can be done by rendering the items visible in the viewport and then updating them as the user scrolls.

Libraries like react-virtualized and react-window can be used for React Windowing/ List Virtualization considering the overall architecture of the application.

It not only improves the memory, and performance of the App but also helps to maintain a smooth scrolling behavior for the user.

So far we have seen ways to write maintainable and robust code for our application, but still, our application may encounter some errors. Here is one way to reduce the number of errors and inconsistencies in your app.

4. Reducing errors and inconsistencies with immutable data structures and properties: -

The word ‘immutable’ (unchangeable) is self-explanatory. Hence, my final tip will be to use data structures (variables) that cannot be changed in the later part of the app wherever possible.

Here are two benefits of immutable data structures: -

  • We may not be able to track all the changes made to a mutable data structure, leading to bugs. Thus, immutable data structures can help to prevent bugs.
  • When mutating a mutable array/ object, the entire data is copied into a new array/ object which can be an expensive task. But, immutable arrays/ objects do not require copying. They simply create a new array/ object with the changes

Thus, I can safely say that immutable data structures are a powerful tool that can help you to improve the performance, reliability, and readability of your React code.

Conclusion: -

Concluding here, there are many best practices that you can follow to improve your React development skills. By following these practices, you can create more reliable, efficient, and maintainable React applications. These might seem overwhelming at first but believe me they will make you a great developer.

Let us all learn and grow as better React Developers. Happy Coding !!!

--

--

Prince Verma
OneAssist Tech

I am a software developer with over 1.5 years of experience in the industry. I have a strong background in frontend development.