DESOSA 2022

ReactJS - Scalability

In the previous three posts, we have discussed the vision, architecture, and software quality of ReactJS. ReactJS is one of the most used front-end JavaScript frameworks. Since many people access ReactJS every day via their web browsers, it is crucial for developers to make sure that their ReactJS application is scalable in terms of time and space performance. In this last post, we discuss the main elements that affect React App’s scalability and its performance and also analyze the changes that can be made to those applications.

Identification of the system’s key scalability challenges

Scalability is the measure of a system’s ability to increase or decrease in performance and cost in response to changes in application and system processing demands. For ReactJS, the system processing demands are determined by the size of the application, and specifically the amount of DOM operations required to update the UI. Updating the DOM is usually the bottleneck when it comes to ReactJS web performance and scalability. 1

Imagine we have an application where data is rendered on a page. If an application renders long lists of data (hundreds or thousands of rows) to the DOM, it can affect performance. Thus, one key challenge of scalability is how to efficiently render large pieces of data to the DOM . Fortunately, techniques like “windowing” exist to improve the rendering performance. React offers react-window and react-virtualized to provide reusable components for displaying lists, grids, and tabular data 2. These can be tailored to your application’s specific use cases.

If we look at big applications that use React - Facebook, Instagram, or Netflix - it is apparent that the framework does great for these single-page applications. Moreover, many developers claim that ReactJS is best built for large web applications because of its ease of creating dynamic applications, improved performance, reusable components, and unidirectional data flow 3. To see the scale of how React can be used we look at Facebook’s use of components. Dan Abramov, the creator of the Redux Library, mentioned that Facebook has around 90,000 components in production4. So what are the key scalability challenges in such large projects? For many businesses, scalability is centered on the following aspects: 5

  • The ease of adding, maintaining, and fixing code.
  • The ease of adding new people to the project
  • The ability to handle complex and heavy tasks.

These aspects and rendering data to DOM mainly depend on how the code is written. The key challenges, therefore, involve how the project is structured and what the design decisions are for code architecture, and this also affects time and space performance of the application. Therefore, the common scalability challenges in React applications are:

  • Rendering large pieces of data to the DOM: “Windowing” is a technique to improve rendering performance. The challenge is up to the developer on how to incorporate this in their specific use case.
  • Decouple logic from components: As an application grows, some component’s logic gets used over and over again. To share the component’s logic, custom hooks try to decouple the logic and make it reusable between other components 1.
  • Use Pure Components where possible: Pure components only shallowly compare the objects and determine if they should be updated using the primary function shouldComponentUpdate()1 6.
  • Too many wrappers: to encapsulate state management logic, higher-order components and render props had to be used. Using many contexts will result in a large tree with many sub-trees, resulting in a wrapper hell. This makes the code prone to errors and also makes debugging harder as one needs to look at a large component tree with many components only acting as wrappers 7.

Addressing these challenges comes with experience, a good understanding of React, and writing good code architecture.

Empirical quantitative analysis under varying workloads

As it was mentioned above, ReactJS is a library that is used to build the application, and thus the performance of the resulting application comes partially from the size of the applications. One of the key elements that downgrade the performance comes from the costly DOM operations to update the UI.

To see the impact of resource usage based on the varying workload, we dive deeper into three different sizes of React applications and analyze CPU time and heap memory usage. Todo is a small sample React application which is for TODO checklist. Shopping Cart is also a sample React application which mocks shopping websites. Lastly, Facebook is one of the well-known example of a large React application.

The resource usage was measured using the following inspection method provided by Chrome.

Figure: Facebook Resource Usage

To approximate the size of the application, we assessed the bundle size of each application. An app’s bundle size is the amount of JavaScript a user will have to download to load the app 8. If the bundle size is too high, then the time performance of the application decreases. Todo has a bundle size of 180KB, and Shopping Cart has a bundle size of 227KB. We could not get the exact bundle size of Facebook, but it is logically estimated to be much bigger than those two small test applications.

Examples Total Time Max JS Heap
Todo 9 (small) 482ms 16.4MB
Shopping cart 10 (medium) 1074ms 18.7MB
Facebook 11 (large) 6472ms 173MB

According to the table above, as the application size grows, CPU time grows as well as the heap size. Heap is a space for storing data where JavaScript stores objects and functions. This implies that more energy will be consumed. It is impossible to drastically reduce the number of React components and maintain exactly same features. However, developers can implement efficiently, aiming for both low energy consumption and better performance. More about this is explained in the upcoming section.

Identification of ReactJS application’s architectural decisions that affect its scalability

The architectural decisions lay with the developer that uses ReactJS to build an application. Many different architectural styles can be applied and each has its effect on scalability and performance.

The performance of React Applications is mostly impacted by the DOM updates. Traditionally, with DOM all components will get updated as the entire list of components gets re-rendered. Instead of using inefficient DOM, ReactJS uses the concept of virtual DOM. It keeps a local copy of the HTML DOM, so only the item which needs to be updated will be updated. While virtual DOM is already improving performance. There are still disadvantages to it.

React uses a Diffing algorithm 12 to minimize the operations to be done at nodes. However, this algorithm also has its downsides. React goes on rendering the whole subtrees instead of rendering the relevant component. If these unnecessary renders are left idle in a React application, unnecessary CPU and memory resources which can be eaten. This results in the following performance-related issues, which are also known as wasted Renders 13:

  • Redundant processing in components that do not update in the DOM.
  • Diffing algorithms keep on updating leaf nodes that do not need to be updated.
  • Diffing algorithm updates components resulting in heavy CPU computation.

When it comes to scalability and maintainability of the code, primary and secondary building blocks are the things a developer can rely on 5. Primary building block means React components, and secondary building blocks comprise of higher-order components (HoC), hooks, render props, or context.

In ReactJS it is extremely easy to merge components into one or to extract new components. Many component patterns exist and can help with refactoring when the structure of the application is changing.

Furthermore, ReactJS is modular, so it is not a problem to extract a separate module in the application and delegate the workload to new coworkers or even separate them. Due to the modular nature of ReactJS, it is also easy to extract a common part of the application, such that it can be reused in different parts of the product or migrated to other applications in the project. Many applications use ReactJS due to its high cohesion, low coupling, and components reusability.

Proposals for the change in React application that can address the identified issues

To resolve the Diffing issues that are mentioned in the previous section, the following methods can be used to improve the performance of the React application architecture:

  • Use the lifecycle hook shouldComponentUpdate(), to avoid both components and their children getting rendered unnecessarily whenever a component’s state changes 2.

  • Use Immutable.js for data that never changes. It allows the developer to compare direct object references instead of doing deep-tree comparisons, which improves performance 13.

There are some other architectural changes that can improve ReactJS performance:

  • ReactJS recommends using the minified production build for testing. The development build includes warnings that can be helpful during development. However, for deploying, use the production version to make React faster.

  • Use a technique known as “windowing”, if an application renders long lists of data. This technique only renders a small subset of the rows at any given time and greatly reduces the re-rendering time of the components as well as the number of DOM nodes created.

Conclusion

Due to the tradeoff existing between time and memory, it is always hard to balance what to sacrifice and optimize at the moment. When building React applications, as lots of design choices can be determined by developers, these three aspects of performance often depend on the experience of developers. Energy consumption issue is hard to resolve and often does not become a priority issue to be considered, because of the technical difficulties that developers need to face.

Throughout four essays, we discussed different topics regarding React. With the help of all these essays, we hope the readers get to know the bright side of ReactJS.

Reference


  1. Sebhastian, N., 2020. 6 Tips and Best Practices for a Scalable React Project [online] blog. Available at: https://blog.bitsrc.io/best-practices-and-tips-for-a-scalable-react-application-db708ae49227 [Accessed: 27-March-2022]. ↩︎

  2. Reactjs.org. 2022. Optimizing Performance – React. [online] Available at: https://reactjs.org/docs/optimizing-performance.html [Accessed: 27-March-2022]. ↩︎

  3. Developers using React. 2020. Is React good for large applications? [online] Available at: https://www.quora.com/Is-React-good-for-large-applications [Accessed: 27-March-2022]. ↩︎

  4. Ambramov, D., 2018. Facebook React with Dan Abramov [online] Software Engineering Daily. Available at: https://softwareengineeringdaily.com/2019/05/16/facebook-react-with-dan-abramov/ [Accessed: 27-March-2022]. ↩︎

  5. Brainhub.eu. 2022. React Security, Scalability, Maintenance & Performance. [online] Available at: https://brainhub.eu/library/react-security-scalability/ [Accessed: 27-March-2022]. ↩︎

  6. ReactJS., 2022. React Top-Level API [online] ReactJS. Available at: https://reactjs.org/docs/react-api.html#reactpurecomponent [Accessed: 27-March-2022]. ↩︎

  7. Kumar, P., 2022. Scalability Issues in React? Here’s How to Manage Them Effectively | CodeForGeek. [online] CodeForGeek. Available at: https://codeforgeek.com/scalability-issues-in-react/ [Accessed: 27-March-2022]. ↩︎

  8. “Analyze your react app’s bundle size and reduce it using code-splitting,” Emma Goto, 22-Nov-2020. [Online]. Available: https://www.emgoto.com/react-bundles-and-code-splitting/. [Accessed: 27-Mar-2022]. ↩︎

  9. Kabirbaidhya, “Kabirbaidhya/react-todo-app: React todo app,” GitHub. [Online]. Available: https://github.com/kabirbaidhya/react-todo-app. [Accessed: 27-Mar-2022]. ↩︎

  10. jeffersonRibeiro, “Jeffersonribeiro/react-shopping-CART: 🛍️ simple ecommerce cart application built with typescript and react,” GitHub. [Online]. Available: https://github.com/jeffersonRibeiro/react-shopping-cart. [Accessed: 27-Mar-2022]. ↩︎

  11. Facebook. [Online]. Available: https://www.facebook.com/. [Accessed: 27-Mar-2022]. ↩︎

  12. Reactjs.org. 2022. Reconciliation – React. [online] Available at: https://reactjs.org/docs/reconciliation.html#the-diffing-algorithm [Accessed: 28-March-2022]. ↩︎

  13. Shah, H., 2022. React Performance - 13 Ways to Optimize Performance of your React App. [online] Insights on Latest Technologies - Simform Blog. Available at: https://www.simform.com/blog/react-performance/ [Accessed: 27-March-2022]. ↩︎

ReactJS
Authors
Jeongwoo Park
Budi Han
Mirijam Zhang
Jahson O'Dwyer wha Binda