6 best practices for developing scalable React projects

When you start working on a new React project, it is recommended that you formulate instructions that you can follow to create an application that scales well. In this post, I want to share the knowledge I have gained about React development over the years using this library. They will help you shape your own React code of practice.











1. Rationally distribute data between local and global application state



React is a library that is responsible for managing the user interface based on the current state of the application. The task of the programmer is to rationally organize the work with state. Some developers prefer to store all the data at their disposal in the Redux repository. This allows them to organize centralized processing of all application data.



But when thinking about what data should be included in the state of the application, it is worth considering whether you need to pass an action to the state management system just to, for example, open a simple drop-down menu. The same goes for, say, the data entered by the user into the feedback form. Do all parts of the application need to know what is entered in such a form? When it comes to what is entered into the form, such data is usually processed by the application in a fairly short period of time. Moreover, they are used only by the component that is responsible for displaying the form on the screen.



Instead of using the Redux store to store everything the application is working with, it is better to store some data in the local state of the components. This will avoid overcomplicating the application architecture.



When thinking about where exactly you need to store some data, it is worth asking yourself the following questions :



  • Do you need access to this data in different parts of the application?
  • Do you need the ability to form something new based on this data?
  • Are different components using the same data?
  • Is it valuable for you to be able to restore the state of the application, which includes this data, bringing it to the form in which it was at a certain point in time (that is, are you interested in debugging with the ability to move along the code execution path in the opposite direction)?
  • Do you plan to cache this data (that is, use the existing state if the application already has it, rather than reload it)?
  • Do I need to keep this data when hot reloading components (during this process, the internal state of the components can be lost)?


Positive answers to the above questions indicate that the data is somehow used outside the component. This means that it makes sense to store them in the global state of the application. It should be noted, however, that components using local state are more independent and predictable.



2. Learn how to test applications and equip your projects with tests from the start



Creating automated tests is very important. The fact is that at a certain point in the work on a React project, manual testing of it will take a lot of time and resources.



At the beginning of a project, when its code base is still relatively small, it is very easy to decide that you do not need to write tests for it. If an application has five to ten components, then creating automated tests looks like an almost pointless routine task. But if a project grows to more than 50 components and contains many higher-order components, manual testing can take an entire work day. And even with this approach, errors may remain in it that no one will notice.



In addition, writing tests helps improve the structure of your code by dividing it into modules. This will help you find errors faster and protect the project from production failures. The point of automated testing is that it helps a growing project develop at a stage when manual testing is no longer able to confirm that the code is working correctly.



However, if you are not in the habit of creating tests, you, having a fairly large project, cannot immediately write them for it. That is why you need to start writing tests from the very beginning. If you're unsure of where to start testing your project, start with integration tests . The point is, the most important thing in testing is to confirm that your components interact correctly with each other.



3. Apply additional tools that help in scaling the application



Usually, at the beginning of the development process of React projects, there is no need to use a large number of auxiliary tools. But, since we are talking about projects that can become quite large, it is worth noting that specialized tools will greatly facilitate work on them. Here's a description of some of them:



  • Using Prettier and ESLint helps programmers on a team write consistent code. These tools can help reduce syntax and other errors in your code. Projects benefit from the use of auxiliary libraries like React Router , date-fns , react-hook-form .
  • TypeScript Redux , , . , .
  • - , React , .
  • Using Bit allows you to organize work with components presented as independent building blocks of an application. This means that you can test and render components in isolation. This approach to working with components makes them easier to maintain and reuse.
  • Instead of create-react-app, you can use the corresponding Next.js tools to create new React applications .


These tools will help you maintain a large React application codebase. But when choosing tools, keep in mind that each of them increases the level of complexity of the project. Before you include anything in your project, study everything well and make an informed decision.



4. Pay attention to the project file structure



One of the best tips I've come across for developing scalable React apps is that organizing your project files and naming them wisely can help speed things up. Some developers often as the main file in the folders that are stored in the directory components, is used index.js.





Files of various components are named the



same.This approach to organizing a project seems to be quite reasonable, since when importing a component in some file, the corresponding instruction is quite simple:



import Button from '../components/Button';


But what if you open the files of such components in an editor?





Everywhere - only index.js



It will be inconvenient to navigate in them. It is not easy to determine which component each belongs toindex.js. However, if you rename these files to match the component names, the import instructions will look less attractive:



import Button from '../components/Button/Button';


How to be in this situation? For example, my team came to the following solution: in the component folder there is a file with a code whose name corresponds to the component name, and next to it is the index.jsone that exports the component.





Component code file and index.js exporting the component



We also put CSS and unit test files in the component directory. With this approach, each component directory contains everything that is relevant to the corresponding component.





Self-contained component



5. Create a library of components



It's best to start building a library of components early on in your project, rather than waiting for it to grow. Components, in the process of working on them, can be designed as stand-alone blocks suitable for repeated use. You can create a library of components using Bit, either by using the bit.dev resource , or by deploying the system at home.



6. Separate the logic of the components from themselves using hooks



As the project grows, you may notice that the logic of some components is used over and over in different places. You can use proprietary hooks to organize the sharing of component logic.



For example, we have an application for calculating points in a basketball game.





Application for scoring in a basketball game



If you look at the code for this application, it would appear that in the filesHomeTeam.jsandAwayTeam.jsuse the same logic to work with the meter. In such a situation, when the same code is used to manage the interface, you can separate that code from the component and put it in a separate file.



Here I separated the code for storing the state of the counter and the logic for increasing the counter into a separate fileutil.js. This file is imported into components.



Hooks are, in essence, ordinary functions that return some value. With their help, you can style code that is intended to be reused in various components.



Outcome



Always keep in mind that developing large-scale React applications is a complex task that requires making decisions that take into account the interests of the users and developers of such applications. The choice of recommendations that makes sense to follow when working on each specific project depends on how good these recommendations are for those who use the project and for those who are developing it.



When choosing the tools and techniques to use in project development, it's worth experimenting with. This will allow you to choose exactly what will benefit your React application. I hope that the tips I shared with you today will be useful to you.



What development tools and techniques do you use when building React projects that need to scale well?










All Articles