Blueprint by Tiny
Return to Tiny.cloud
Return to Tiny.cloudTry TinyMCE for Free
Search by

How to optimize react apps – a tutorial

Team Tiny

November 22nd, 2022

10 min read

Written by

Team Tiny

Category

How-to Use TinyMCE

React impacts front-end developers everyday. Recent results from the Stack Overflow Developer survey 2022 show React is still favored after all these years – 44% of survey respondents who are professional developers, make use of the framework. 

One of the best aspects of the framework is that it makes UI updates efficient with a virtual Document Object Model (DOM), so that web pages load faster. Why, then, do moderately sized React web apps still lag, and perform poorly?

Even React needs optimization, from time to time.

React doesn’t magically make your app faster. But by understanding how React works, and how the components live through the component lifecycle, it represents an essential learning for professional developers.

Performance improvements come from measuring and optimizing how and when your components render. Fortunately, React provides the tools and functionalities necessary to make those measurements meaningful and manageable.

This optimization tutorial demonstrates methods to improve your React app load speed. 

It covers strategies you can use to achieve a fast app speed for: 

  • Developers who are at the early setup stage 
  • Developers who are at the building stage 
  • Or developers who have built their app and are ready for the production stage. 

Note: For more information on integrating the TinyMCE into the React framework , check out the React rich text editor integration page, which contains further information.

 

HatTip: This article’s content and advice would not have been possible without the work of William Wang 

Contents

Where to start optimizing react?

What are common React performance issues?

    How to optimize react app during setup

        Using Eslint-plugin-react

        Enabling Gzip on your web server

        Binding functions early

    How to optimize react apps when building

        Using Multiple Chunk files

        Making data immutable

        Using a React.PureComponent

        Confirm if React should update components

    How to optimize react apps during production

        Controlling the production build

        Performance measurement tools

        Visual performance management tools

Creating a fast react app

Where to start optimizing React?

During the initial render, React builds a virtual DOM – a structure made from your app’s components. It might look like this:

An optimal React component loading pattern
An optimal React component loading pattern

Given a part of the data changes, what we want React to do is re-render only the components that are directly affected by the change (and possibly skip even the diff process for the rest of the components). The following is an optimal loading of react components, with only the required components represented in gray:

React loading all components in a sub-optimal way

However, what React ends up doing is a sub-optimal loading of components, where React loads all components:

A sub-optimal loading pattern of React and components

In the image above, all of the blue nodes are rendered and different, as well as the required gray nodes, resulting in wasted time and computation resources. This is where we'll primarily put in our optimization efforts Configuring each component to only render-diff when it is necessary, allows us to reclaim these wasted CPU cycles.

Developers of the React library took this into consideration and provided a hook for us to do just that: a function that lets us tell React when it’s okay to skip rendering a component.

What are common React performance issues?

Issues with performance might be hiding until you launch your React app on other environments. If you suspect any of the following are happening to your React app, check through the following sections for optimization strategies. These are three common performance issues:

1. Re-rendering 

A component in your app is re-rendering code when modified at runtime, without modifying the original code. Re-rendering can cause performance issues across all different components.

2. Clumped component tree 

When components are grouped together, the overall app performance can decline. Best practice is to place commonly updated regions into their own, isolated components.

3. Not using pure components 

A pure component only re-renders if the props are different when React compares the previous prop state to the current state. More on this optimization can be found in the section on pure components in the following paragraphs.

How to optimize React app during setup

Getting off to a good start can make all the difference when building a React app. The following optimizations are important considerations for the start of your new project.

Using Eslint-plugin-react

Use ESLint for almost any JavaScript project. React is no different. With eslint-plugin-react, you are forcing yourself to adapt to a lot of rules in React programming that can benefit your code in the long run, and avoid many common problems and issues that occur due to poorly written code.

Enabling Gzip on your web server

React 's bundle JS files are commonly very big, so to make the web page load faster, we can enable Gzip on the web server (Apache, Nginx, etc.)

Modern browsers all support and automatically negotiate Gzip compression for HTTP requests. Enabling Gzip compression can reduce the size of the transferred response by up to 90%, which can significantly reduce the amount of time to download the resource, reduce data usage for the client, and improve the time to first render of your pages.

Check the documentation for your web server on how to enable compression:

Apache:

mod_deflate;


Nginx:

ngx_http_gzip_module;

Binding functions early

It is very common to see functions bound to the context of the component inside the render function. This is often the case when we use these functions to handle events of child components.

// Creates a new `handleUpload` function during each render()
<TopBar onUpload={this.handleUpload.bind(this)} />
// ...as do inlined arrow functions
<TopBar onUpload={files => this.handleUpload(files)} />

This causes the render() function to create a new function on every render. A much better way of doing the same is:

class App extends React.Component {
    constructor(props) {
        super(props);
        this.handleUpload = this.handleUpload.bind(this);
    }
    render() {
        …
        <TopBar onUpload={this.handleUpload} />
        …
    }
}

How to optimize React apps when building

If you’ve started building your project, there are still steps you can take to optimize and add speed to your React app.

Using multiple chunk files

For single-page React web apps, we often end up bundling all of our front-end JavaScript code in a single minified file. This works fine for small to moderately sized web apps. But as the app starts to grow, delivering this bundled JavaScript file to the browser in itself can become a time consuming process.

If you are using Webpack to build your React app, you can leverage its code splitting capabilities to separate your built app code into multiple “chunks” and deliver them to the browser on an as-needed basis.

There are two types of splitting:

  • Resource splitting
  • On-demand code splitting

With resource splitting, you split resource content into multiple files. For example, using CommonsChunkPlugin, you can extract common code (such as all external libraries) into a “chunk” file of its own. Using ExtractTextWebpackPlugin, you can extract all CSS code into a separate CSS file.

This kind of splitting helps in two ways. It helps the browser to cache those less frequently changing resources. It also helps the browser to take advantage of parallel downloading to potentially reduce the load time.

A more notable feature of Webpack is on-demand code splitting. You can use it to split code into a chunk that can be loaded on-demand. This can keep the initial download small, reducing the time it takes to load the app. The browser can then download other chunks of code on-demand when needed by the application. Check on the Webpack Code Splitting docs for more information.

Making data immutable

What if you could use a React.PureComponent but still have an efficient way of telling when any complex props or states have changed automatically? This is where immutable data structures make life easier.

The idea behind using immutable data structures is simple. Whenever an object containing complex data changes, instead of making the changes in that object, create a copy of that object with the changes. This makes detecting changes in data as simple as comparing the reference of the two objects.

You can use Object.assign or _.extend (from Underscore.js or Lodash):

const newValue2 = Object.assign({}, oldValue);
const newValue2 = _.extend({}, oldValue);

Even better, you can use a library that provides immutable data structures:

var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set('b', 2);
assert(map1.equals(map2) === true);
<span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;">var map3 = map1.set('b', 50);
</span>assert(map1.equals(map3) === false);

Here, Immutable.Map is provided by the library Immutable.js.

Every time a map is updated with its method set, a new map is returned only if the set operation changed the underlying value. Otherwise, the same map is returned.

For more information about immutability, check on the following: 

  1. Toptal’s resource on immutability in JavaScript with Redux
  2. The TinyMCE article on immutability as a programming principal

Using a React.PureComponent

To ease and automate this optimization technique, React provides what is known as a “pure” component. A React.PureComponent is exactly like a React.Component that implements a shouldComponentUpdate() function with a shallow prop and state comparison.

A React.PureComponent is more or less equivalent to this:

class MyComponent extends React.Component {
    shouldComponentUpdate(nextProps, nextState) {
        return shallowCompare(this.props, nextProps) && shallowCompare(this.state, nextState);
    }
    …
}

As it only performs a shallow comparison, you may find it useful only when:

Your props or states contain primitive data.

Your props and states have complex data, but you know when to call forceUpdate() to update your component.

Confirming if React should update components

By default, React runs and renders the virtual DOM, and compares the difference for every component in the tree for any change in its props or state. But that is obviously not reasonable.

As your app grows, attempting to re-render and compare the entire virtual DOM at every action will eventually slow down.

React provides a simple way for the developer to indicate if a component needs re-rendering. This is where the shouldComponentUpdate method comes into play.

function shouldComponentUpdate>(nextProps, nextState) {
    return true;
}

When this function returns true for any component, it allows the render-diff process to be triggered.

This gives you a simple way of controlling the render-diff process. Whenever you need to prevent a component from being re-rendered at all, simply return false from the function. Inside the function, you can compare the current and next set of props and state to determine whether a re-render is necessary:

  function shouldComponentUpdate>(nextProps, nextState) {
    return nextProps.id !== this.props.id;
}

How to optimize React apps during production

The production build steps also have their own set of optimizations that you can run to add further speed to your optimized React app.

Controlling the production build

When developing a React app, you are presented with really useful warnings and error messages. These make identifying bugs and issues during development a bliss. But they come at the cost of performance.

If you look into React’s source code, there’s a lot of if (process.env.NODE_ENV != 'production') checks. These chunks of code that React is running in your development environment, isn’t something needed by the end user. For production environments, all of this unnecessary code can be discarded.

If you bootstrapped your project using create-react-app, then you can simply run npm run build to produce the production build without this extra code. If you’re using Webpack directly, you can run webpack -p (which is equivalent to webpack --optimize-minimize --define process.env.NODE_ENV="'production'".

Performance measurement tools

Don’t start optimizing code that you feel may be slowing your app down. Instead, let React performance measuring tools guide you through the path to take.

React has a powerful tool, designed  just for this function. Using the react-addons-perf library you can get an overview of your app’s overall performance.

The usage is:

Import Perf from 'react-addons-perf'
Perf.start();
// use the app
Perf.stop();
Perf.printWasted();

This prints a table with the amount of time components wasted in rendering. The library provides other functions that let you print different aspects of the wasted time separately (e.g., using the printInclusive() or the printExclusive() functions), or even print the DOM manipulation operations (using the printOperations() function).

Visual performance management tools

If you’re a visual person, then react-perf-tool is just the thing you need.

react-perf-tool is based on the react-addons-perf library. It gives you a more visual way of debugging performance of your React app. It uses the underlying library to get measurements and then visualizes them as graphs. More often than not, this is a much more convenient way of spotting bottlenecks, and you can easily use it by adding it as a component to your application.

How to create a fast React app

To make the most of React, you need to leverage its tools and techniques. A React web app’s performance lies in the simplicity of its components. Overwhelming the render-diff algorithm can make your app perform poorly in frustrating ways.

Before you can optimize your app, you’ll need to understand how React components work and how they’re rendered in the browser. The React lifecycle methods give you ways to prevent your component from re-rendering unnecessarily. By eliminating those bottlenecks you’ll have the app performance your users deserve.

Although there are more ways of optimizing a React web app, fine tuning the components to update only when required yields the best performance improvement.

Did you know that React is one of the most popular integrations for TinyMCE? If you have a React project in the works and want to take the content creation experience to the next level, click here to get started on setting up your TinyMCE-React component in the docs. For a more guided, step-by-step walkthrough on how to integrate React with TinyMCE, check out the following resources: 

  1. The tutorial post on TinyMCE Angular integration
  2. The pressure test on rich text editors: comparing popular rich text editors Angular integrations.
ReactTinyMCETutorialUse Cases
byTeam Tiny

Powering more than 40% of the world’s websites. Here to educate and empower the world through all things TinyMCE and more.

Related Articles

  • How-to Use TinyMCE

    How to add drag and drop in your app’s rich text editor

    by Joe Robinson in How-to Use TinyMCE
Subscribe for the latest insights served straight to your inbox every month.

Deploy TinyMCE in just 6 lines of code

Built to scale. Developed in open source. Designed to innovate.

Begin with your FREE API Key
Tiny Editor
Tiny logo
Privacy Policy - Terms of Use© 2022 Tiny Technologies Inc.TinyMCE® and Tiny® are registered trademarks of Tiny Technologies, Inc.

Products

  • TinyMCE
  • Tiny Drive
  • Customer Stories
  • Pricing