< Back to blog
PUBLISH DATE:
UPD:
Alex PletnovAlex PletnovChief Technical Officer

Why and How to Refactor Your React Code?

Think about code formatting, get rid of unnecessary <div>’s and <span>’s, use functional React components, try to avoid arrow function in render, and do not repeat yourself!

Refactoring React

Before I go straight to refactoring, I would need you to answer one simple question: what does it mean to develop an application? Usually, this means producing a piece of software that meets requirements by implementing certain features. And how do we do that? We collect customer requirements, estimate them, and develop features one by one. Right?

Almost.

Do Not Forget About Bugs

Yes, errors do occur. Depending on the development process, software complexity, technical stack, and many other parameters, the number of bugs may vary. A business cannot afford critical issues in production. To minimize the probability of such, you should pay particular attention to the QA process. Yet, the QA theory claims that it is usually impossible to run a 100% test of the app and to cover all possible scenarios. Nonetheless, to achieve the optimal result, the team spends a lot of time testing software and fixing issues, and this is the need that each customer should understand and prioritize.

Mind the Technical Debt

Yet, this coin has a flip side. The longer the development and testing process takes, the more technical debt you incur. So, what does "technical debt" stand for?

Technical debt is a metaphor comprising all the quality-related issues you have in the code, which will require spending additional resources in the future.

Technical debt occurs due to a variety of reasons, such as:

  1. The business pushes to release new features faster.

  2. The testing is insufficient.

  3. The requirements are changing rapidly.

  4. The developers are inexperienced.

Technical debt should be documented. If you do not leave to-do's in the code, most likely, you will forget about the issue, and even if you have time for it in the future, you will not remember to fix it.

Understand the Importance of Refactoring

Usually, you need to spend some time refactoring the existing code in order to solve code-quality issues and, thus, to lower technical debt.

But what is refactoring?

It is the process of restructuring the existing code without changing its external behavior. And that is actually something that might be difficult to understand for business people managing the project.

– Will we get any new features?

 – No. 

– Will we at least fix some bugs? 

– Also no. 

 – What will we get then? 

– …

Working with technical debt helps to avoid bugs. Furthermore, to add fixes or changes to the project, we always need to read the old code. Therefore, refactoring and keeping good code quality will help us to keep development at a good pace. 

Sometimes, a business indeed might not need it. For instance, if that is a prototype or Proof of Concept, or if there are business priorities that cannot be switched, you can do without refactoring. But in most cases, cutting off refactoring would not be a wise thing to do. Also, you might spend a really huge amount of time on refactoring if the developer is a perfectionist, which makes no sense either.

Therefore, you need to strike a balance. You should not spend more time on refactoring than you will save in the future.

Start Refactoring Your React Code

Think about code formatting

Some people add trailing commas, and some not. Some use single, while others double quotes for string. If you work in a team, maintaining the common code style can be really burdensome. And inconsistency in code style can make your code look dirty and hard to read. Thus, if you haven’t thought about using code formatting tools before — that’s a high time to do so. 

One of the most popular and easy-to-use React refactoring tools is Prettier. You can just add it to the project, and it will take care or formatting for you. Prettier has some default style settings. But you can change them by your preferences by adding .prettierrc file with your formatting rules.

In my projects, I add such setup to .prettierrc:

{
"printWidth": 120, 
"singleQuote": true,
“trailingComma”: “none”
}

You can also automatically reformat the code before committing with pre-commit hooks

Get rid of unnecessary <div>’s and <span>’s

When React 16.2 was released in November 2017, a lot of React developers sighed in relief. Prior to that, for a component to return a list of children, it was necessary to wrap the children in an extra element, such as <div> or <span>. With React 16.2 we received improved support for returning components’ children. Now developers can use so-called fragments. They look like empty JSX tags (<> … </>). With the help of fragments, you can pass a list of children to the component without adding extra nodes to the DOM.

Think about names

Don’t be lazy to think over names of the components and variables. Every name should be self explainable.

Have you ever seen code snippets like this?

const modifyData = data.map(x => [x.a, x.b]))  

What does it do? If you cannot understand the purpose of a variable from its name – it is time to rename it! This will help you and your team to easier understand the logic. It will also eliminate the time spent on making changes to existing components in the future.

Don’t Repeat Yourself

DRY principle was first formulated in the book The Pragmatic Programmer. It states that "every piece of knowledge must have a single, unambiguous, authoritative representation within a system". 

In other words, you need to put the repetitive code blocks into separate reusable components. 

Making your code DRY has a lot of benefits. It can save you a lot of time. If you need to change this code in the future, you will only do that in one place. Also, you will never have to worry that you forgot to make changes in some places. Furthermore, you will keep the components cleaner and increase readability of code.

To keep your components DRY and small, you can follow two simple rules:

  1. If you use a code block for more than two times, it’s time to extract it.

  2. If you exceed a predefined number of lines in a component (e.g. 100 lines), there probably is the logic which can be extracted. Divide it into smaller components by functionalities.

Use functional over class components

With the introduction of Hooks in React 16.8, we received the access to React class features in functional components. Hooks solve a bunch of problems frequently encountered by developers during the last years. useEffect hook, as React docs suggest, allows us to group the component logic into small functions based on what pieces are related (instead of grouping the logic based on lifecycle methods). This helps us to better restructure our logic. All in all, refactoring React components with the help of hooks makes the code cleaner and reduce the amount of code.

Here is a very basic example: fetching the data after the component has mounted and refetching it based on the props that were updated. 

In a class component we would write something like this: 

class BookList extends React.Component {
	componentDidMount() {
    	this.props.fetchBooks(this.props.bookGenre);
	}
	componentDidUpdate(prevProps) {
    	if (prevProps.bookGenre !== this.props.booksGenre) {
        		this.props.fetchBooks(this.props.bookGenre);
    		}
	}
     // ...
}

With React hooks it will look like this:

const BookList = ({bookGenre, fetchBooks}) => {
	useEffect(() => {
    		fetchBooks(bookGenre);
	}, [bookGenre]);
// ...
}

Books fetching logic is now gathered in one place. useEffect hook will run after mount and each time the props ([bookGenre]) in square brackets change. Much cleaner, isn’t it? Furthermore, you can extract the similar stateful logic and reuse it in different components by creating your custom hooks. You can read more about custom hooks in official React documentation.

Try to avoid arrow function in render

Have you ever see such code?

 

render() {
   return (
     <div>
       ...
       <button onClick={() => this.setState({ flag: true })} />
       ...
     </div>
   );
 }

For sure – yes. What is a problem with it? Every time a component is rendered, the new instance of such a function is created. Actually, it is not a big deal in case the component is rendered one or two times. But in other cases, it can really affect performance. So, if you care about performance, declare the function before using it in render:

changeFlag = () => this.setState({ flag: true })
  render() {
   return (
     <div>
       ...
       <button onClick={this.changeFlag} />
       ...
     </div>
   );
 }

Make the bundle smaller

If you are using a third party library, you should not load all of it if there is no need.

Sometimes you can stumble upon an import which uses only one method from there, such as:

import lodash form 'lodash'
 ...
 const certainProps = lodash.pick(userObject, ['name', 'email']);
 ...

Instead it is better to use: 

import pick from 'lodash/pick'
...
const certainProps = pick(userObject, ['name', 'email']);
...

Now you do not load the whole library, just the method which you need here.

To Wrap Up

Let's review the steps you should take to refactor the React code:

  • Think about code formatting

  • Get rid of unnecessary <div>’s and <span>’s

  • Think about names

  • Don’t Repeat Yourself

  • Use functional over class components

  • Try to avoid arrow function in render

  • Make the bundle smaller

Yet, ideal refactoring is refactoring that does not actually occur. At KeenEthics, we train our developers to think forward and to write a high-quality code, which would minimize the probability of bugs and issues. We also carry out regular code reviews, not only within one team but also between teams.

Do you need help with code refactoring?

Our software development engineers have experience of taking up ongoing projects and refactoring all the existing code. Check the service page to learn more about React development services that we offer.