If you’re a frontend developer engaged in building highly interactive user interfaces, you’ve most likely got React in your toolkit. While working on your React-powered creations, you should be careful to do things in tune with the React best practices. This will help to keep your code better organized.
React is a JavaScript library for developing user interfaces. React library was created by Facebook. React allows for integration with many exciting components, libraries and frameworks. Admittedly, developers can make their own components.
Before the best practices, I would suggest Test-driven Development when you develop a react application. Test-driven Development means write a test first and then develop your code according to the tests. It is easier to identify the bugs. If you follow another Software development process when you find a bug, write a test first.
Today, we take the topic head on and show you the most fundamental of the React best practices:
div s
File organization is not only the best practice for react applications, but also it is the best for other applications as well. The file structure of create-react-app is one possible way of organizing your react files. While there is not necessarily one file structure that is better than another, it important to keep your files organized. In React, your file structure will grow rapidly, considering every component has at least one file associated with it. Keep an assets folder that contains top-level CSS, images, and font files. Maintain a helpers folder to put other files for any kind of file for functionalities. Keep all the files related to a component into one folder. Usually, the component folder contains more than a single component file, such as test file CSS and one or more component files. If there are any minor components used by a particular component only, better to keep those all small components in the component folder. When you keep your large components in their own folder and the small components that are used by the components are in a subfolder is easier to understand the file hierarchy. developers mainly named the main component file inside a file index.js. This can become cumbersome to navigate once you have several files, all named as index.js. The solution for this is to add a package.json file to each of your components folders, set the main entry point for this corresponding folder. For instance, for button component main entry point is Button.js. Adding package.json to each folder is not a good practice but It helps to easily handle your files. So we can add the following package.json file inside the button component folder.
{
"main": 'Button.js'
}
When you use Redux in your React project you can use Rails-style or Domain-style or “Ducks” pattern folder structure according to your project. In Rails-style pattern, separate folders are used for “actions”, “constants”, “reducers”, “containers”, and “components”. In Domain-style pattern, separate folders are used per feature or domain, possibly with sub-folders per file type. “Ducks” pattern is similar to domain style, but it explicitly ties together actions and reducers, often by defining them in the same file. However, folder structure could be something developers wish but there should be an easy way to handle components. React says, it doesn’t have opinions on how you put files into folders. New teams to react use Duck style. When they get matured they start to use rails. Rails has its advantage of understanding the project easily.
That’s exactly what you should do. You should move files around until they feel right.
As we all know, React will work with large components. But if we break them into small sizes, we can reuse them. Small components are easier to read, test, maintain, and reuse. Most beginners in React create Class components even when they aren’t using component state or life cycle methods. Functional components are more efficient for simple components.
import React, { Component } from 'react';
class Button extends Component {
render() {
const { children, color, onClick } = this.props;
return (
<button onClick={onClick} className={`Btn ${color}`}>
{children}
</button>
);
}
}
export default Button;
The above Class component could be written as below.
import React from 'react';
export default function Button({ children, color, onClick }) {
return (
<button onClick={onClick} className={`Btn ${color}`}>
{children}
</button>
);
}
Advantages of using Functional Components.
this
binding.When you are using functional component you have no control over the re-rendering process. When something changes or even component changes itself, React will re-render functional components. In former react versions has a solution to use React.PureComponent
. PureComponent allows shallow props and state comparison. When props or content of the component or component itself changed component will re-render. Otherwise, PureComponent skip re-render and reuse the last rendered result instead.
After React v16.6.0 React introduces a new feature that was memo. Memo shallowly compare props. When props or content of the component or component itself changed component will re-render. Based on the comparison react will either reuse last rendered result or re-render. Memo allows you to create an unadulterated functional component. Memo obliterate the use of stateful components and PureComponent
.
Each functional component should have one function that means one functional component is equal to one function. When you are creating a functional component with one function you can improve the reusability of that component.
Not only in React but also in all application development the common rule is keeping the code is succinct and tiny as much as possible. React best practices instruct to keep the error-free code and incisive code. Don’t Repeat Yourself (DRY) is a principle of software development focused at minimizing repetition of software patterns, replacing it with abstractions or using data normalization to avoid redundancy. In code fomatting you can use your own style guide or use a popular fully-fledged style guide(Airbnb React/JSX Style Guide, Facebook Style Guide, etc). If you start to follow anyone of the style follow that don’t confuse with others.
When creating an array of JSX elements react requires you to add a key prop to your element. This is commonly done using a map function which in turn results in people using an index to set to the key property. This is bad! React uses the key property to track each element in the array and due to the collapsing nature of an array. This can easily result in the wrong information being rendered in the wrong place. This is especially apparent when looping through class components with the state.
When Creating React component it is important to keep in mind that you are still building an HTML document. People tend to get divitis
in React which ultimately leads to incorrect HTML.
return (
<div>
<li>Content</li>
</div>
);
In the above example, the div
would end up being a direct child of ul
which is incorrect HTML vs the below example where the li
end up being the direct child of ul
, forming correct HTML.
return (
<li>Content</li>
);
We can use another approach that uses <React.Fragment>
tags. <React.Fragment>
was introduced in React v16.2, we can use them instead of the extraneous <div>
tag.
Add a comment in the application where necessary. Removing the ability to comment from an application meant I HAVE to write literate code, no exceptions. It gives untidy free code sections. In general, comments are a wart that stipulates poor design, especially long-winded comments where its clear the developer didn’t have a clue what the heck they are doing and tried to make up for it by writing a comment.
Since functional components don’t require this
binding you’ll want to use them whenever possible. But if you are using ES6 class, you’ll want to bind this manually since React doesn’t auto bind the function within that component. Here are some examples for doing so.
Example 1: Bind in render
class Foo extends Components {
constructor(props) {
super(props);
this.state = { message: "Hello" };
}
logMessage() {
const { message } = this.state;
console.log(message);
}
render() {
return (
<input type="button" value="Log" onClick={this.logMessage.bind(this)} />
);
}
}
adding the following snippet to the render known as bind in render
onClick={this.logMessage.bind(this)}
This way is clear, succinct and works but it can cause a slight performance issue because a new function is going to be called every time this component re-renders which could be frequent.
Example 2: Arrow function in render.
class Bar extends Components {
constructor(props) {
super(props);
this.state = { message: "Hello" };
}
logMessage() {
const { message } = this.state;
console.log(message);
}
render() {
return (
<input type="button" value="Log" onClick={() => this.logMessage()} />
);
}
}
Adding the following snippet to the render known as arrow function in render.
onClick={() => this.logMessage()}
This way is clear, succinct like example 1, but like example 1 it will also create a new function every time this component renders.
Example 3: Bind in constructor
class Hello extends Components {
constructor(props) {
super(props);
this.state = { message: "Hello" };
this.logMessage = this.logMessage.bind(this);
}
logMessage() {
const { message } = this.state;
console.log(message);
}
render() {
return (
<input type="button" value="Log" onClick={this.logMessage} />
);
}
}
Adding the following snippet to the constructor known as bind in constructor.
this.logMessage = this.logMessage.bind(this);
This way is going to solve the potential performance issue of Examples 1 and 2. Don’t forget to call super in the constructor.
Example 4: Arrow function in Class property
class Message extends Components {
constructor(props) {
super(props);
this.state = { message: "Hello" };
}
logMessage = () => {
const { message } = this.state;
console.log(message);
}
render() {
return (
<input type="button" value="Log" onClick={this.logMessage} />
);
}
}
Adding the following snippet to the class known as arrow function in class property.
logMessage = () => {
const { message } = this.state;
console.log(message);
}
This way is very clean, readable and it’s going to avoid performance issues of Examples 1 and 2 and avoid the repetition in Example 3. Be aware however that this method does rely on experimental features and it’s not an official part of the ECMA Script specification. You are able to experiment language features by installing and configuring the babel package and apps created by a create react app has many features enabled.
We can divide the heading into two subheadings such as.
When you use props in the initial state the problem is that the constructor is called when the component is created. So the constructor is only called once. If you change something to the props next time, the component state will not update and it remains the same as the previous value. You can fix the problem using react lifecycle method componentDidUpdate
. The componentDidUpdate
method updates the component when props changed. componentDidUpdate
won’t be invoked on the initial render. But, using props in the initial state is not the best practice.
Initializing states as class fields is the best practice. Initializing component state with the constructor is not that much bad practice but it increases the redundancy in your code and makes some performance issues. When you initialize the state inside the class constructor it unwantedly calls super and remembering about props, it makes performance issue.
class SateInsideConstructor extends React.Component {
constructor(props) {
super(props)
this.state = {
counter: 0
}
}
/* your logic */
}
Another issue is when you are going to initialize state inside the constructor think about the number of lines that you need, want you need constructor()
,super()
?
import React from 'react'
class MyComponent extends React.Component {
state = {
counter: 0
}
/* your logic */
}
Name a function or a component after typing the scripts because they should be easily identifiable. For example, you choose the name of a component like FacebookButton
instantly because of the component code. But in the future, you may use that component as TwitterButton
,YoutubeButton
. So, the best practice is to name that component as Button
. Normally when you finish the function, you should be able to choose the common name for the component and function. Naming in the end increases the reusability.
In React, when we can categorize the components by state. There are stateful and stateless. Stateful component store component’s state information and provide necessary context. In the other way around stateless components have no memory and can’t give context to the part of the user interface. Stateless components are scalable, reusable and like pure JavaScript functions. Separates the stateful fetching logic from rendering stateless logic. One better way is to use a stateful component to fetch data and another stateless component to display that fetched data.
After React v16.08 there is a new feature called ‘React Hooks’. React Hooks write stateful functional components. React Hooks obliterate the use of class components.
If data is not being directly rendered in the render method it should not be in the component state. Data that is not being directly rendered can cause unnecessary re-renders.
According to the React Docs React doesn’t guarantee that stage changes are applied immediately. Therefore reading this.state
right after calling setState
is a potential pitfall because this.state
may not actually be what you think it is.
const { ischecked } = this.state;
this.setState({ischecked: !ischecked});
Instead of updating the state within an object like the above snippet, we can use the following function.
this .setState((prevState, props) => {
return {ischecked: !prevState.ischecked}
})
The above function will receive the previous state as its first argument, and props
at the time the update is applied as its second argument. State update is an async operation, so to update the state object, we need to use updater function with setState
.
When you are working in React remember that you are using JSX (JavaScript Extension) instead of HTML. The component created by you should be named in the upper camel case, a.k.a Pascal Case. The upper camel case means words are written without spaces, and the first letter of each word is capitalized. For example, If there is a component named as selectbutton
then you should name it as SelectButton
instead of selectbutton
. Using the upper camel case helps to JSX to differentiate the default JSX element tags from created elements. However, you can use lower case letters to name a component but it is not a best practice.
The ‘prop-types’ is a library for type checking props and it can help prevent bugs by ensuring you are using the right data types for your props. React.PropTypes
has moved into a different package since React v15.5. React.PropTypes
package gives us the ability to type check a component’s props and give it default values. So you are going to use an external library by npm install.
npm i prop-types
Import the library, add PropTypes
to the component, set the data type accordingly and if the prop is required, add isRequired
like below.
import React, { Component } from "react";
import PropTypes from "prop-types";
class Welcome extends Component {
render() {
const { name } = this.props;
return <h1>Welcome, {name}</h1>;
}
}
Welcome.PropTypes = {
name: PropTypes.string.isRequired
};
Default values can be assigned to the props using defaultProps
. When a component does not receive its props, it refers to the defaultProps
that has been assigned. It is not necessary to assign defaultProps
, if you have marked your props as required. In the code snippet below you can see all the default values that have been assigned to the props for ModalButton. For this example, I used React Bootstrap framework.
import React, { Component } from "react";
import { Button } from "react-bootstrap";
import PropTypes from 'prop-types'
class ModalButton extends Component {
render() {
return <Button variant={this.props.variant}>{this.props.children}</Button>;
}
}
ModalButton.defaultProps = {
variant: "outline-info",
children: "Info"
};
ModalButton.propTypes = {
variant: PropTypes.string,
children: PropTypes.string
}
ReactDOM.render(<ModalButton />, document.getElementById('root'));
Always define explicit defaultProps for all optional props
It is important to note that do type-checking using PropsTypes
after assigned the defaultProps
. Therefore it type-checks the default values assigned to the props as well.
During my internship works we faced a problem in styling, and especially theming. The CSS was loaded in the development environment but it didn’t load in the production environment.
When you have a big CSS (SCSS)file you can use the global prefix followed by the Block-Element-Modifier convention to avoid name collision. When your application becomes bigger this method is not scalable. So you have to evaluate your CSS(SCSS) file. There is another approach to extract CSS via webpack’s Mini CSS Extract Text plugin (it requires webpack 4 to work) but it creates heavy dependency on the webpack. If you use this method, testing your component is difficult. Best practice is to have an easily testable application therefore, following this approach is not the best practice.
EmotionJS, Glamorous and Styled Components are some of the new arrived CSS in JS libraries. You can use these depending on your use cases. When you need to spit out a compiled CSS for production you could use the EmotionJS library. When you have a complicated theming issue you can use Glamorous and Styled Component libraries.
Not only in React but also in other programming languages you should do testing. Testing is important, because it ensures that the code behaves as expected and testable easily and quickly. In best practice, create a __Test__
folder inside the component folder. Create test files with the name of the component with a .test.js
suffix. You can use Jest as a test runner and Enzyme as a testing utility for React. My Teammate Kavindu Vindika wrote about Jest and Enzyme Testing, if you want you can check it out.
Crash testing a component is a simple fast way to ensure all your components are functioning without crashing. Component crash testing is easy to throw into every component you make.
import React from 'react'
import ReactDom from 'react-dom'
import App from '.'
it('renders without crashing', () => {
const div = document.createElement{'div'};
ReactDOM.render(<App/ >, div);
ReactDOM.unmountComponentAtNode(div);
});
You should be doing obviously more extensive testing than the crash testing. If you write more test cases it will give more test coverage for your code. But, very least you should be doing some kind of crash testing. In crash testing what we do is create an element and then it uses ReactDom and mounts whatever component you imported into that the div was just created and then it unmounts div.
A true React developer do proper testing for the entire react application.
ESlint keeps your code nice and tidy by yelling at you with squigglies. You can link this to your IDE. The best practice is to keep your own ESLint configuration file.
A good Developer fix all ESlint errors and warnings rather than disabling that error.
Prettier is a code formatting tool. Prettier has a set of rules for code formatting and indention. You can use Sonarlint to check spells, function length and suggestions for better approaches. Using Husky is not only a good practice for React but also a good practice for Git. You can define the husky in package.json file. Husky prevents your application from bad commit and bad push.
Code snippets help you to code best and trend syntax. They keep your code relatively error-free. You can use a lot of snippet libraries such as ES7 React, JavaScript (ES6) code snippets, etc.
React Developer Tools is available as an extension for Chrome and Firefox. If you use Safari or another standalone shell use the following command to install it.
npm install -g react-devtools@^4
If you are looking for a web application built in React, you can see in the Components tab, the component hierarchy. If you click on a component you can view the props and state of that component. As you can see React Developer Tools extension is very valuable tool to test and debug and really understand what’s happening with that app.
This article describes the best practices in React. These practices improve your application performance, your application code, and your coding skills. Woohoo!!! 🙌
Happy coding 😎
#reactjs #javascript #webdev