Analysis and optimization of React applications

Original author: Houssein Djirdeh
  • Transfer
People like me who struggle for high performance sites often spend a lot of time on this. So now I’m going to once and for all solve the problem of low-speed web resources whose interface is written in React. Namely, I suggest that everyone who reads this should stop using React today. The author of the material, the translation of which we publish today, of course, jokes. Here we will talk about how to optimize the performance of React applications. By the way, before you start, let's think about why website optimization is generally needed. Perhaps we can say that it is needed in order for the site to be used by more people than before optimization.





Introduction


How to optimize the site? How can you evaluate the benefits of optimization for site users? And why do you need to think about such indicators?

We will try to answer these questions by looking at the easiest way to create React applications - using the create-react-app (CRA) tool . A new project created using this tool has the following dependencies:

  • The main library reactthat allows you to work with React components: 2.5 Kb.
  • A library react-domthat allows components to be displayed on the page, turning them into structures suitable for insertion into the DOM tree: 30.7 Kb.
  • A small amount of code, which includes the template of the first component: about 3 Kb.

This data is obtained for React 16.6.3.

In order to find out how long it will take to download a new CRA application on your Moto G4 phone, you can use the WebPageTest service .


Website loading time on Moto G4 phone using different networks

This application, a variation of “Hello, World”, is hosted on Firebase hosting, it is being studied loading it in the Chrome browser using three types of connections:

  • 4G (9 Mbps)
  • 3G (1.6 Mbps)
  • Slow 3G connection (400 Kbps)

Here you need to consider network delays.

Why did I use the Moto G4 for the experiment? This is a simple inexpensive phone, similar to those phones that, in the form of basic devices, are used by many people in developing countries. On a 4G network, the application loaded in 2 seconds. In a slow 3G network, it took more than 4 seconds for a page to go online.

Although these metrics are quite interesting, they are not particularly useful if you don’t know who your users are. What you define as “slow” may be completely different from what I or someone else considers “slow”. And your perception of the “fast” loading of the site may be distorted by the device and network connection you use. If you include a desktop computer connected to the Internet via a wired connection in this experiment, you can see how great the difference can be between “fast” and “slow” loading a site.


Site load time on the desktop computer and on the Moto G4

In order to improve the performance of React applications, which are built using the React library, as they say, out of the box, React DOM improvements are outlined that are aimed at simplifying some things. So, the event system contains many polyfills, which, for many new browsers, are not needed, and the development team is considering options for removing or simplifying them, if possible. You can watch it here .

Can I measure the current level of website performance?


A typical React application can contain many third-party components and libraries. This means that the performance of the "Hello, World" application does not provide us with particularly valuable information on how real applications load. Is there a way to find out how high performance most sites built using some technology (like React) are?

The HTTP Archive resource may help us answer this question . This is an open source platform that focuses on observing how the web is built. This is done by monthly crawling millions of sites, analyzing them using WebPageTest and recording information about them. This information includes the number of queries, metrics regarding data loading, sizes of transmitted data, and other indicators.

Here's another interesting tool - an extension for Chrome called Library-Detector-for-Chrome . It allows you to figure out which JavaScript libraries are used on the page. It has recently been included as a page audit tool in Lighthouse. This suggests that the information that this extension provides can be obtained for many sites whose information is stored in the HTTP Archive. This can help those who want to analyze the test results of thousands of sites that use a specific JavaScript library (the mechanism for determining React is here ).

The complete HTTP Archive dataset is publicly available and can be found on BigQuery. After researching 140,000 sites using React for loading them in an artificially simulated mobile environment (data set 2019_01_01), we managed to find out the following:

  • The median of the First Meaningful Paint indicator (first significant display, time for drawing important elements) was 6.9 s.
  • The median of the Time to Interactive indicator (time to interactivity, load time of interaction elements) was 19.7 s.

You can explore this data yourself.

It takes almost 20 seconds for the user to start interacting with the site. And this, in general, is happening, so to speak, here and now, although it may look implausible. This can be seen on large sites when working with them from weak devices on slow communication lines. In addition, now I would like to voice several reasons why these data should be considered with a degree of skepticism.

  • There are many factors that influence site performance. Among them - the amount of JavaScript code sent to the user, the number of images and other materials displayed on the page, and so on. It will incorrectly compare the performance of any React-based sites with the performance of a page labeled “Hello, World” if other factors are not taken into account.
  • If you try to get the data by replacing the name of some other library in the React request, you will get very similar numbers.

In order to get accurate data about what kind of performance realistically existing sites using a certain library demonstrate, a lot of work needs to be done.

JavaScript code growth


The common problem of modern websites, not tied to a specific library, is related to the amount of JavaScript code that a client usually has to load when browsing. The HTTP Archive already has a good account of this. In a nutshell, here's what the median values ​​of JavaScript volumes downloaded from websites in different years look like:

  • 74.7 Kb - mobile web pages, December 15, 2011.
  • 384.4 Kb - mobile web pages, December 15, 2018.

It should be borne in mind that this data was obtained after processing millions of pages. There are probably thousands of atypical sites that distort this indicator. This is a viable idea. Therefore, we will try to find out how this indicator looks for the first 10,000 sites from the Alexa ranking:

  • 381.5 Kb - mobile web pages, December 15, 2018 (here is the request ).

All this allows us to conclude that nowadays websites are being created that include more JS code than sites that were created several years ago. This is an important observation. Sites have become larger, they have become more interactive and more complex, and the volume of JS-code of these sites is gradually growing every year. You probably already heard about this, but the more JavaScript code you send to the browser, the more time it takes to parse, compile, and execute it. This, as a result, slows down the site.

It is important to note that each site is unique, as well as the user base of each site. Many developers, whose sites include more than 300 KB of JS code, do not face the fact that most of their users suffer from performance problems, and this is completely normal. However, if you are worried that it might be difficult for your users to view your React site, in order to assess the real situation, it is best to start with profiling.

Page profiling and analysis


Profiling and analyzing React applications can be viewed from two perspectives:

  • Firstly, it is about evaluating the performance of components. This affects how users interact with the site. For example, if a list is displayed by clicking on a button, this should be done quickly, but if hundreds of components are re-rendered during this operation, even though it is not necessary, this operation will be perceived as slow.
  • Secondly, we are talking about how soon the application is brought into working condition. That is, how much time after the start of loading the site, the user will be able to interact with him. The amount of code sent to the user during the loading of the first page of the site is an example of a factor affecting how quickly the user can start working with the application.

Performance assessment and component optimization


Let's try to express in one sentence the meaning of the React reconciliation algorithm, or the essence of what is called the “virtual DOM”. It will look like this: “React takes steps to distinguish between the new DOM tree and the old tree in order to understand what exactly in the user interface should be updated when the data in the component changes.” This creates a much lesser load on the system than re-rendering the entire application for every change in state or properties ( here you can read about the difference between O (n 3 ) and O (n)). Here is an article by Dan Abramov, where you can find explanations about reconciliation.

Even taking into account the fact that these optimizations are built into the internal mechanisms of React, one can always encounter a problem when the components in the application are rendered repeatedly when this should not happen. In small applications, this may not be noticeable, but it can seriously affect the performance of applications that display hundreds of components on their pages.

Unnecessary re-rendering of components is done for many reasons. For example, functions that work inside components may not be as effective as they might be, or perhaps a whole list of components is redrawn when only one new element is added to this list. There are tools that you can use to find out which component trees have been rendering for too long. Among them, the following can be noted:

  • The Chrome Developer Tools Dashboard.
  • React Developer Tool Profiler.

▍ Performance analysis using the Chrome Developer Tools performance panel


React uses the User Timing API to measure the time taken at each step of the component's life cycle. Performance information for React applications can be collected and analyzed using the Chrome Developer Tools. This allows you to understand how effectively the components are connected, displayed on the page and disconnected during user interaction with the page or when it reloads.


Component Performance Analysis

Here is some good material on this topic, dedicated to researching the performance of applications written using React 16 using the Chrome developer tools.

The User Timing API is only used during development. It, in production, is turned off. In such conditions, faster implementations of such mechanisms can be used, without having a serious impact on performance. It was the need for such mechanisms that became one of the reasons for the development of the newer API Profiler.

▍Analysis of performance using the profiler from the React developer tools


With the release of library react-dom16.5 in the tools of the React developer, you can use a new panel called Profiler. It allows you to analyze the performance of component rendering. This is done using the Profiler API, which collects information about the execution time of operations for all components that are re-rendered.

The Profiler panel is a standalone tab in the React developer tools . Here, as with the Chrome Developer Tools toolbar Performance panel, you can record information about user actions and page reloads in order to collect data for analyzing component performance.


Data collection using the React developer tools.

After the data collection is completed, the so-called “fiery graph” will be displayed, showing the time required to render the components on the page.


The fiery profiler graph

Here you can switch between different commits, or states when DOM nodes were added, deleted or updated. This allows you to get more information about how much time is spent on various operations with components.


Viewing information about commits in the profiler

The screenshots presented here represent data obtained as a result of recording user actions performed in a simple application. The application downloads a list of trending GitHub repositories when a button is clicked. As you can see, there are only two commits here:

  • One is for the loading indicator, which is displayed during the loading of the list of items.
  • Another represents the moment when the call to the API is completed and the list is displayed in the DOM.

The figure on the right side shows useful metadata that includes commit information or component data, such as properties and state.


Metadata

Working with the React profiler, you can view other data represented by various graphs. You can read more about the React profiler in this post from the React blog.

To complicate our example a bit, consider a similar situation, but now we will make many calls to the API to download trend repositories in different programming languages ​​(like Golang, JavaScript, and so on). As you might expect, with this approach, we have more commits at our disposal.


Increase in the number of

commits while complicating the scheme of working with the application Later commits differ in longer schedules, they have more yellow color. This means that the time required for all components to complete the rendering grows as the size of the list of elements on the page grows. This is due to the fact that each component in the list undergoes re-rendering with each new call to the API. This helps to identify a problem that can be quite easily resolved. The solution is that the items in the list do not need to be rendered again when new items are added to the list.

▍ Minimizing unnecessary component re-rendering operations


There are many ways to get rid of unnecessary operations for re-rendering React-components, or at least to minimize the number of such operations. Let's consider some of them.

  • You can use the component lifecycle method of shouldComponentUpdate () :

    shouldComponentUpdate(nextProps, nextState) {
      // true нужно возвратить только при соблюдении определённых условий
    }
  • You can use PureComponent to construct class-based components :

    import React, { PureComponent } from 'react';
    class AvatarComponent extends PureComponent {
    }
  • For functional components, you can use memo :

    import React, { memo } from 'react';
    const AvatarComponent = memo(props => {
    });
  • You can memoize Redux selectors (for example, using reselect ).
  • You can optimize the output of very long lists by using virtualization (for example, using react-window ).

Here and there - a couple of useful videos, which discusses the use of the React profiler for finding bottlenecks in applications.

Performance assessment and application optimization


In addition to analyzing DOM mutations and component re-rendering operations, there are other higher-level phenomena that are worth exploring. For a comprehensive assessment of site performance, you can use Lighthouse .

There are three ways to test a web page using Lighthouse:

  • Using the Node.js. Command Line Interface
  • Using the Chrome extension .
  • Use the Audits toolbar of the Chrome Developer Tools.

Here's what Lighthouse looks like in the Audits panel.


Lighthouse on the Audits

Lighthouse panel usually does not require a lot of time to collect all the data it needs from the page and to perform many checks of this data. After these operations are completed, Lighthouse displays a report with summary information.

In order to understand that loading a page into the browser involves loading too much JavaScript code, and to conclude that the amount of this code should be reduced, you need to pay attention to the following phrases from the report:

  • Eliminate render-blocking resources
  • JavaScript boot-up time is too high
  • Avoid enormous network payloads

If Lighthouse reports these issues because the page uses too large a JS bundle, the very first thing worth considering as a way to fix the problem is splitting the bundle. The fact is that if the code can be divided into fragments, some of which are needed only for working with certain pages of the site, then we have no reason not to use this opportunity.

▍ JS bundle separation


One way to split the code into parts is to use dynamic imports:

  import('lodash.sortby')
    .then(module => module.default)
    .then(module => doSomethingCool(module))

The import syntax may look like a function call, but it allows you to import any module asynchronously using the promises mechanism. In this example, the method is first imported sortbyfrom the library lodash, and then the method is executed doSomethingCool().


Application for sorting numbers.

In this example, the following occurs:

  1. The user clicks a button to sort the three numbers.
  2. Imported lodash.sortby.
  3. A method is called doSomethingCool()that sorts the numbers and displays them in the new DOM node.

This is an extremely simple, artificial example, because if someone needs to sort numbers on a web page, then he will probably just use the method Array.prototype.sort(). But I hope that this example helped me show why the use of dynamic imports when a user performs certain actions may be useful.

The dynamic import syntax is relatively new; it is currently at the third stage of the TC39 adoption of new JavaScript features. This syntax is already supported in Chrome and Safari , as well as bundles Webpack , Rollup and Parcel .
If we talk about React, then there are abstractions created to simplify the process of breaking code at the component level using dynamic import technology. One example of the implementation of this mechanism is React.lazy:

import React, { lazy } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));

One of the main problems associated with the asynchronous loading of various parts of the application is to work with delays in the application that the user may encounter. For this, there is a component Suspensethat can be used to “suspend” the display of a tree of a certain component on the screen. When using it together with React.lazy, it is possible, if the code of the required component is still loading, show the user a loading indicator:

import React, { lazy, Suspense } from 'react';
import LoadingComponent from './LoadingComponent';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const PageComponent = () => (
  
    
  
)

The component Suspensestill does not work when applying server-side rendering. If you want to use code separation techniques in React applications that are rendered on the server, use a library like the one given in the React documentation loadable-components.

import React from 'react';
import loadable from '@loadable/component'
import LoadingComponent from './LoadingComponent';
const AvatarComponent = 
  loadable(() => import('./AvatarComponent'), {
    LoadingComponent: () => LoadingComponent
  });

LoadingComponentcan be used with loadable-componentduring loading of the main component as an indicator.

Please note that in order to use the library loadable-componentsin server rendering, you need to configure something .

Let's think about where exactly in the application it is worth using code separation techniques. Perhaps the easiest way to separate the code is based on the routes. The React documentation has an explanation of how this might look like using a React router and Suspense.

▍ Is it worth it to do code separation that relies on page scrolling?


Here is another interesting library for code separation, react-loadable-visibility , which is built on top of theloadable-components Intersection Observer library and web API. It can be used to load components as they become visible as you scroll through the page.

import React from 'react';
import loadableVisibility from 'react-loadable-visibility/loadable-components'
const AvatarComponent = loadableVisibility(() => import('./AvatarComponent'), {
  LoadingComponent: Loading,
})

▍About caching of what is worth caching


Service workers are web workers that run in the background of a browser while viewing a page. The main goal of service workers is to implement in them a certain functionality that runs in a separate thread and is able to improve the user's experience with the site. This includes caching of important files, which leads to the fact that when a user re-visits the site, the browser can download something by contacting the service worker and not the server, which can speed up page loading.


Accelerating page loading using caching


Workbox
is a set of libraries that simplifies the inclusion of service workers in the project, eliminating the need for the programmer to write all the necessary code from scratch. Using CRA 2.0, in order to use this mechanism, it is enough to delete only a couple of characters from the file src/index.js. This will give you the opportunity to use a standard service worker with basic caching capabilities.

  import React from 'react';
  //...
  // Если вы хотите, чтобы ваше приложение работало бы без подключения к интернету 
  // и быстрее загружалось бы, вы можете изменить ниже
  // unregister() на register(). Обратите внимание на то, что при работе с сервис-воркерами
  // нужно учитывать некоторые особенности. 
  // Подробности о них смотрите здесь: http://bit.ly/CRA-PWA
  serviceWorker.unregister();

Details about service workers and the library Workboxcan be found in this material.

▍ Server rendering and streaming data


The technology of server-side website rendering is based on the idea of ​​reducing the load on user devices by sending ready-made HTML code generated on the server to the browsers that is exactly the same that would have turned out in the browser as a result of the work of the program forming the page. This allows users to see the content of the pages much faster than when they need to download some JS code to form the page, and then wait for it to finish executing.

In order to ensure the correct operation of this mechanism, the site developer must be sure that the browser uses the DOM structures generated on the server, instead of independently re-creating the markup (for example, using the methodhydrate()in React). It may look like the page is loading faster, but it can increase the time it takes for the user to interact with the page.

When working with React 16, you can take advantage of the streaming capabilities of server-side component rendering. Instead of using the method renderToString()to form an HTML string, you can use the method renderToNodeStream()to return a Node Readable stream.

Streaming data from the server allows the client to receive and in turn output different parts of the HTML document instead of displaying the entire document at once. Although server-side rendering always improves the metric associated with the first output of the application page to the screen, this approach can further improve the metric.

If you use React to develop static sites, then instead of the above method, use the renderToStaticNodeStream method .

▍Using pre-rendering in cases where server-side rendering is not applicable


The definition of server rendering is somewhat vague due to the fact that there are different approaches for the server to send, instead of a full set of certain materials, only some of them, represented by static content, intended for output when accessed to some address. There are also different approaches to bringing the browser what is received in this way from the server to a healthy state.

Pre-rendering, or static rendering, is a cross between server-side rendering of pages at the time the browser accesses the server and rendering that is fully performed on the client. This approach usually involves the creation of HTML pages for each route during the assembly of the project and the provision of these pages to the user after all the application materials are ready for use.

If you want to use this technology in your application, libraries like react-snap , which use the capabilities of Puppeteer , can help you with this .

Here is some good material on various approaches to server rendering.

БOn extracting important styles described as CSS-in-JS


Many React developers, for various reasons, use CSS-in-JS libraries like emotion and styled-components. Among such reasons, one can note the possibility of using styles whose scope is limited by the component, automatic creation of selectors based on the properties passed to the components, and others. If you do not use due diligence when using CSS-in-JS technology, you may run into a problem that all styles will be calculated at runtime. This means that styles will be applied only after the JavaScript bundle of the page has been executed, which leads to the fact that the user can observe the unstylized content of the page for some time. As with any other performance issues, this problem is exacerbated when weak mobile devices or slow network connections are used to work with the site.


A situation in which the user for some time sees the unstylized content of the page (taken from here )

If your application already uses some kind of server rendering, you can fix the problem with styles by extracting the most important of them. The emotion and styled-components libraries support this feature. Styles can be retrieved into the readable stream of the Node. Glamor has a separate library that allows you to do the same.

Removing important styles can greatly improve the situation for users working on weak devices or with slow network connections.


The Preact application is shown here, but this example allows you to evaluate the possibilities of extracting styles ( source )

If all you need from CSS-in-JS technology is the use of styles whose scope is limited by components and you do not want to overload the application libraries that implement a wider functionality, perhaps the astroturf library is suitable for you . Using it, you will not get all the features available in a typical library of this kind, but you will have the opportunity to work with controlled styles of components, the use of which will not create additional load on the system during application code execution.

▍Accessibility sites


If a certain application is called “progressive”, this means that its creators have tried to ensure that all users have the opportunity to access at least some of its part. If people with disabilities cannot work with your site, this means that it cannot be called progressive.

In order to identify problems with the availability of a certain page, Lighthouse is perfect. To find problems specific to React elements, you can use the React A11y project .

In addition, you might consider using react-ax to audit a finished, rendered application, not just its JSX code.

▍ Improving the ability to add sites to your home screen


Does your site work well on mobile devices? Do you have service workers who cache some materials, which allows the application to work without an internet connection? Is your application so useful that users may want to place an icon for quick access to it on the home screen of their devices?

If you answer all these questions in the affirmative, then you need to write a web application manifest for your site . This will increase the convenience of users to work with the application when it is "installed" on their mobile devices. The manifest allows you to customize a lot of things, including the application icon, background color and theme color.

When using create-react-app, the application template created by this tool is equipped with a standard manifest file:

{
  "short_name": "React App",
  "name": "Create React App Sample",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

Miscellaneous


Here are some ideas that are aimed at optimizing the work of programmers. Their use, in addition, leads to a decrease in the volume of application code. The smaller the amount of application code, the better. Why is this so? The fact is that the more compact the application code is, the less data will have to be transferred from the server to the browser and the faster the pages of the application will load.

▍Atomic CSS


The methodology for using atomic CSS styles (Atomic CSS) involves creating classes that solve extremely narrow problems and are small in size. For example, with this approach, a separate class is used to assign a blue background to the button:


A separate class is used to configure the button property padding:


Etc. Although this leads to the need to add a very large number of values ​​to the attribute of classmost DOM nodes, it gives the advantage that the developer has to write much less CSS code than usual. This is achieved through the use of libraries responsible for the automatic configuration of selectors. One such library is Tachyons .

Limiting the scope of styles to the boundaries of a component using atomic classes has become a common practice for many developers. And libraries seem to tachyon-componentseven allow you to apply these styles using an API similar to the API styled-components:

import styled from 'tachyons-components'
const Button = styled('button')`
  bg-blue pa2
`

Although this may not be the main reason that developers use libraries for working with atomic styles, eliminating the need to create new CSS selectors through the use of a fixed set of “one-time” classes means that the amount of CSS code sent to the browser will always be stay the same.

▍Hooks


Hooks allow you to do a lot of things with functional components that were previously only available when working with class-based components. Working with the state of a component is just one example:

import { useState } from 'react';
function AvatarComponent() {
  const [name, setName] = useState('Houssein');
  return (
    
      
       

This is a picture of {name}

             
         
 ); }

Hooks can be used to solve the following tasks:

  • Inclusion of state in a component without using class-based components ( useState ).
  • Включение в компонент побочных эффектов без использования компонентов, основанных на классах (useEffect).
  • Повторное использование одной и той же логики в разных компонентах благодаря созданию собственных хуков.

All this allows you to include logic in components that can be reused elsewhere in the application. Prior to the advent of hooks, the recompose library was used to take advantage of some of these features .

Here is a post from the React Conf event, at the beginning of which you can find a detailed explanation of the concept of hooks.

Although the remarkable capabilities of hooks themselves will lead to their wide distribution, it can be noted that their use can also help in reducing the size of packages of JavaScript code of applications. As he writesDan Abramov, speaking of an increase in the React library after adding support for hooks, it amounted to approximately 1.5 Kb (minified and compressed version). It is very likely that using hooks will help reduce the size of bundles because the code that uses hooks is better than the code that uses components based on classes and can be minified.

Summary


Here we looked at a lot of issues related to optimizing the performance of React applications. Here is a brief summary of the steps that anyone who wants to make their applications faster can take:

  1. Measure the performance of application components using one of the following tools:

    • The Chrome Developer Tools Dashboard.
    • React Developer Tool Profiler.
  2. Минимизируйте число ненужных операций повторного рендеринга компонентов

    • Там, где это применимо, воспользуйтесь методом жизненного цикла компонента shouldComponentUpdate().
    • Для компонентов, основанных на классах, используйте PureComponent.
    • Для функциональных компонентов используйте React.memo.
    • Воспользуйтесь технологией мемоизации селекторов Redux (например, с помощью reselect).
    • Примените технологии виртуализации при выводе очень длинных списков (например, с помощью react-window).
  3. Измерьте общую производительность приложения с помощью Lighthouse.
  4. Улучшите общую производительность приложения, применив следующие подходы к оптимизации:

    • Если вы не пользуетесь серверным рендерингом — подумайте о разбиении кода компонентов с помощью React.lazy.
    • Если вы пользуетесь серверным рендерингом — разделяйте код компонентов с использованием библиотеки наподобие loadable-components.
    • Используйте сервис-воркеры для кэширования материалов, которые стоит кэшировать. Вам в этом может серьёзно помочь Workbox.
    • Если вы пользуетесь серверным рендерингом — используйте потоки вместо строк (с помощью renderToNodeStream и renderToStaticNodeStream).
    • Серверный рендеринг вам не подходит? Тогда задействуйте предварительный рендеринг с использованием библиотек наподобие react-snap.
    • Извлекайте самые важные стили при использовании библиотек, нацеленных на реализацию технологии CSS-in-JS.
    • Постарайтесь сделать так, чтобы ваши приложения были бы доступны как можно более широкому кругу пользователей. Рассмотрите возможность использования библиотек React A11y и react-axe.
    • Equip your project with a web application manifest if you think it will be convenient for mobile users to work with it by calling it from the home screen of their devices.

When an open source project like React gains immense popularity, it’s natural to expect the following from it:

  • Improving its API, going through the creation of tools that simplify the creation of applications.
  • The emergence of third-party libraries, which, again, simplify the creation of applications.

The phrase “simplifying application development” can mean a lot of things. This includes facilitating the development of web projects that load quickly on users' devices and work quickly.

Dear readers! How do you optimize your React applications?


Also popular now: