One great thing that React gives us is almost full freedom on how we will organize and write our code. This is one of the top reasons why React is so popular after all. Unfortunately, sometimes that can be a bad thing. Why? Due to this freedom of choice we have, there are many different code styles, which can make it harder to understand and maintain codebase, especially when it comes to a larger number of developers or teams. Not to mention that some of them use React features in the wrong way.
The ultimate goal of application development shouldn’t be just to make the application work. The harder part is when it comes to adding new features or maintaining existing ones. An additional problem may be that the job will not be done by the same person who developed the primary code. If we don’t keep our code clean, our codebase will become very complex and few will want to work on it.
I experienced many situations when I was looking at small portion of code, even well-packed, not having a clue what it does. Not so rarely that was code I wrote.
So, we need to ensure that our code is easy to understand for other developers, too, and for ourselves when we have to work on it some time later.
Reading documentations, following best practices and looking at other’s code helps me to improve my code readability. I gathered a list of things that helps me write React code which will be easier to maintain and to spot possible errors. Some of them may seem trivial or unnecessary, but I find them useful when I code or debug. The great thing is that some of this work can be automated using linting tools.
Clean code
Writing clean code is generally preferable, no matter which technology we use. It is one of the best techniques to make your code easier to understand, without adding stuff like comments or documentation.
I try to keep up with clean code best practices by practicing these things:
- giving variables and functions meaningful names
- making functions do one thing — one that is in its name
- creating functions that have max 3 parameters (less is even better)
- avoiding complex nested if statements
- not adding unnecessary context
Avoid duplications
Even if it’s probably the easiest way to add some feature that is very similar to existing one by copy/paste technique, it isn’t recommended solution. Not only it will result in more code, but it creates room for potential errors later, when you have to update your feature on several places in your code. Same situation is with smaller portions of code like if-else or switch-case statements.
The programming principle that prevents this problem is called DRY — Don’t Repeat Yourself and it is one of the most fundamental principles in programming. It has several derivations but for the example above, the solution is to implement abstraction on your repeating features.
TypeScript
Although it has some drawbacks, TypeScript has a lot of positive stuff and it is still gaining popularity. It gives us type-checked system, which makes it easier to track types of parameters or return types. By using TypeScript we don’t have to use 3rd party libraries to validate props or state objects.
Organizing imports
I organize imports in 3 groups:
- 3rd party libraries (React, lodash, etc) imports
- company libraries imports (if there are any)
- locale imports
After grouping them, I sort them by the name of the file, so it can be easier to find import later.
Before grouping and sorting imports
After grouping and sorting props
If you work with webpack, you can define aliases in your webpack configuration, which will make your imports shorter and more readable.
Sorted variables, props, state
Sorting is an optional thing, but I find it useful when searching for variable or function to check what is its type or parameter for example. Before sorting, I do grouping props by objects and functions, which also makes it more readable and searchable.
Before grouping and sorting props
After grouping and sorting props
Directly updating props or state
Many will say this is even weird to mention, but it happens a lot. This is probably because it works in some situations, but it is generally anti-pattern and it is advised by React dev team not to do it. Props should be updated from parent component and state should be updated using setState or set functions.
Functions defined before use
When creating a new function I prefer to place it before function(s) where it’s used. Reason for that is when I’m going through code later I will check this function and be familiar with it before I even come to the place where it’s used, which prevents me from jumping back and forth in the code.
Arrow functions
One of the greatest features of ES6 are definitely arrow functions. Not only they solve problem with binding class components functions, they are simple to write and understand.
Standard function
Arrow function
Small and reusable components
Components, similar to functions, should represent one element and its logic. On the contrary, everything is more complex when dealing with large components.
To be more reusable component should have props to manipulate as much of its content.
Functional vs Class components
With React v16.8 we have functional components with hooks, which covers most of general usage of React components. Functional components have less code, which is always better. Although, in some situations class components are preferable, for example components with complex state object which needs to be updated on multiple places in our component.
Class-based component
Functional component
async/await
Except from making our code cleaner, async/await give us several more benefits: error handling of both synchronous and asynchronous code with same try/catch, easier working with conditionals, debugging and chained async operations.
classnames
Another package that will make our code cleaner when we need to combine multiple CSS classes, where some of them are conditional.
Code refactor
From time to time we need to go through our code and see if there is something we can simplify, decouple or refactor. When we add new functionality there is a great possibility that some of our components will need refactor: moving to shared folder, adding new props etc.
Another situation when we should do refactoring is when we acquire new knowledge about the technology from which our application can benefit. We should try to update our code to use the latest and best optimized stuff.
As I said at the beginning, React is a very subjective technology with a lot of different code styles. What suits someone does not suit someone else. And that is okay. When working in teams, the point is in finding what suits best to your team based on how that affects work and productivity. This is, after all, why we chose a technology or way of work.
I hope you find useful some of the things I shared and that it will improve your work.