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!
Before I go straight to refactoring, I 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.
Related services
React JS Development Services
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 this probability of such, you should pay particular attention to the QA process. Yet, the QA theory claims it’s usually impossible to run a 100% app test and cover all possible scenarios. Nonetheless, to achieve the optimal result, the team spends a lot of time testing software and fixing issues. 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:
- The business pushes to release new features faster.
- The testing is insufficient.
- The requirements are changing rapidly.
- The developers are inexperienced.
Technical debt should be documented. If you don’t 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 won’t remember to fix it.
Understand the Importance of Refactoring
Usually, you need to spend some time refactoring the existing code to solve code-quality issues and, thus, lower technical debt.
But what is refactoring?
It is the process of restructuring the existing code without changing its external behavior. That’s 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 avoid bugs and to keep development at a good pace.
Sometimes, a business indeed might not need it. For instance, if that’s a prototype or Proof of Concept, or if there are business priorities that can’t be switched, you can do without refactoring. But in most cases, cutting off refactoring wouldn’t be a wise thing to do. Also, you might spend a huge amount of time refactoring if the developer is a perfectionist, which makes no sense either.
Therefore, you need to strike a balance. You shouldn’t spend more time on refactoring than you will save in the future.
7 Tips to Start React Code Refactoring
Think about code formatting
Some people add trailing commas, and some don’t. Some use single, while others double quotes for string. Maintaining the common code style can be really burdensome if you work in a team. And inconsistency in code style can make your code look dirty and hard to read. Thus, if you haven’t thought about using React refactoring tools before — that’s 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 of 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 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 the names of the React components and variables. Every name should be self-explainable.
Have you ever seen code snippets like this?
const BookList = ({bookGenre, fetchBooks}) => {
useEffect(() => {
fetchBooks(bookGenre);
}, [bookGenre]);
// …
}
What does it do? If you cannot understand the purpose of a variable from its name – it’s time to rename it! This will help you and your team to easier understand the logic. It’ll 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 you forgot to make changes in some places. Furthermore, you will keep the components cleaner and increase the readability of the code.
To keep your components DRY and small, you can follow two simple rules:
- If you use a code block for more than two times, it’s time to extract it.
- 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 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 reduces the amount of code.
Here’s a fundamental example: fetching the data after the component has mounted and refetching it based on the updated props.
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 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
render() {
return (
… this.setState({ flag: true })} /> …
);
}
Have you ever seen such code?
For sure – yes. What’s the problem with it? Every time a component is rendered, a new instance of the function is created. Actually, it’s not a big deal in case the component is rendered one or two times. But in other cases, it can affect performance. So, if you care about performance, declare the function before using it in render:
changeFlag = () => this.setState({ flag: true })
render() {
return (
… …
);
}
Make the bundle smaller
If you are using a third-party library, you shouldn’t load all of it if there is no need.
Sometimes you can stumble upon an import using 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 don’t load the whole library, just the method which you need here.
To Wrap Up
How to refactor React code? Let’s summarize the steps explaining React code refactoring process:
- 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 doesn’t occur. At Keenethics, we train our developers to think forward and to write 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.
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.