Effective React Code Splitting: A Practical Guide

Read it in 10 Mins

Last updated on
07th Jun, 2022
Published
19th Jan, 2022
Views
5,024
Effective React Code Splitting: A Practical Guide

Despite its simplicity, JavaScript has the ability to generate complex codes. The wide range of classes and modules available is one of the reasons for this. Most large JavaScript programs and frameworks have a lot of dependencies, which can quickly add up to a lot of code in a seemingly simple project.

The increase in speed provided by code splitting is a standard procedure in large React applications, and it can calculate whether a user continues to use a web application or leaves. According to various research, web pages take less than three seconds to have an impact on users, so even fractions of a second can make a significant difference. As a result, aiming for a load time of three seconds or less is ideal. Here is an article on usereducer hook in React. 

The more code in a project, the slower it will load in the browser. As a result, you'll need to weigh the size of your dependencies against the performance you expect from your JavaScript on a regular basis. A simple solution is to use code-splitting, which involves breaking down the application's JavaScript into small, modular bundles called chunks that can be loaded on-demand when a specific feature is accessed. The goal is to keep individual chunks under 100–150 KB for the application to become interactive in 4–5 seconds, even on slow networks.

What is code splitting?

Many JavaScript frameworks combine all of their dependencies into a single file, making it simple to incorporate JavaScript into an HTML page. Because all of the JavaScript is in one place, the bundle only requires one link tag, and there are fewer calls required to set up the page.

The overhead of interpreting and executing the code causes the page load to slow down rather than speed up once a bundle reaches a certain size. Each page has its own tipping point, which you should test to find out where it lies. Everything depends on the loaded dependencies.

For example:

We can use dynamic import().

Before:

import { add } from './math';
console.log(add(10, 15));

After:

import("./math").then(math => { 
console.log(math.add(10, 15));});

You can see after the code splitting, we don’t need the add component, we only need the math file.

As soon as Webpack gets this type of syntax, code-splitting is started automatically. When using the Create React App, it is already set up and can be used immediately.

The key to code separation is determining which parts of a page require different JavaScript dependencies. You can use code splitting to leave certain dependencies out of bundles on purpose, then add them only where they're required. This also means that they aren't loaded until they're required; only loading JavaScript when it's required reduces page load time.

This may appear to be contradictory at first because the page is still trying to load the same lines of code; however, the difference is because the page may not execute all of the code it loads. If a page's dynamic element requires a large dependency, that dependency may cause noticeable page lag. If, on the other hand, the dependency is only loaded when the dynamic element is used, the lag may be minimal.

Code Splitting in React - Using React.lazy() and Suspense

React.lazy allows imports lazy loading in a variety of situations. It does not yet support server-side rendering, but its feature set compensates. With just one line of code, you can dynamically import a dependency and render it as a component using the React.lazy function. The component must be rendered inside another component that displays fallback content if the dynamic import fails.

This can contain error content, but it is not required. If error content is present, it must be contained within a special type of component known as an Error Boundary. To ensure proper display, the Error Boundary component must be placed above any dynamically loaded components.

Using React.lazy() :

//Without React.lazy()
import OtherComponent from ‘./OtherComponent’;
const MyComponent = () => (
<div>
    <OtherComponent />
</div>
)

// With React.lazy()
const OtherComponent = React.lazy(() => import(‘./OtherComponent’));
const MyComponent = () => {
<div>
    <OtherComponent />
</div>
)

React.lazy is a function that requires a dynamic import(). This must resolve to a module with a default export containing a React component as a Promise.

Using React.Suspense:

A component made with React.Lazy() is required for rendering when it is loaded. As a result, you should show some kind of placeholder content, such as a loading indicator, while the lazy component is loading. This is precisely the purpose of React.Suspense.

React.Suspense is a component for wrapping lazy components. A single Suspense component can wrap multiple lazy components at different hierarchy levels.

import React, { Suspense } from 'react';
const About = React.lazy(()=>import('./About'))
const App = () => {
  return (
    <Suspense fallback={<div>WAIT</div>}>
      <About></About>
    </Suspense>
  );
};

export default App;

Effective React Code Splitting: A Practical Guide 

When there is a load in your file, then you can the output as above. It will render WAIT till the file completely load.

Code Splitting - Conditionally Rendered Components

You can conditionally use the React.lazy() function to ensure that a component is rendered only when it is required.

To speed up page loading, OSF (Open Storefront Framework) for building commerce storefront makes extensive use of server-side rendering. In some cases, however, a component will contain code that should not be rendered in advance, such as a conditionally displayed user interface element. A popup that appears when an item is added to the shopping cart, for example, should be rendered only when the shopper clicks the Add to Cart button.

The Suspense component accepts a fallback prop that accepts the React elements you want to be rendered as placeholder content while all the lazy components are loaded.

The fallback prop can accept any React element that will be rendered while the Component is loading.

The Suspense Component can be positioned above the Lazy Component. Furthermore, multiple lazy components can be encapsulated in a single Suspense Component.

Here is the example of multiple lazy components in a single suspense component:

import React, {Suspense} from 'react';
const ComponentOne = React.lazy(() =>  import('./ComponentOne'));  
const ComponentTwo = React.lazy(() => import('./ComponentTwo'));  
const App = () =>  
    (<Suspense fallback={<div>Loading...</div>}>
      <ComponentOne></ComponentOne>
      <ComponentTwo></ComponentTwo>
    </Suspense>  
    );

export default App;

Effective React Code Splitting: A Practical Guide 

So, this will be your output of the above code.

Code Splitting by Routes

App routes are a good place to start when it comes to code splitting. Break an application down into chunks per route, then load that chunk when the user navigates that route. Under the hood, webpack creates chunks and serves them to the user on demand.

We simply need to create an asyncComponent and import the desired component using the dynamic import() function.

You can perform route-based code splitting without using an external package by using React.lazy() and React.Suspense. Simply convert all route components in your app to lazy components and wrap them in a Suspense component.

Example:

import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route exact path="/" element={<Home/>}/>
        <Route exact path="/about" elementt={<About/>}/>
      </Routes>
    </Suspense>
  </Router>
);

The Suspense in the above code will show Loading... (the text which we add in the fallback placeholder) until the Lazy components are loaded.

Effective React Code Splitting: A Practical Guide 

Code Splitting & SSR:

You render a page on a server, send it to a client, load any necessary JS, then hydrate HTML, and it comes to life.

All scripts must be loaded by the time you call hydrate, so you must know all the chunks required to render some page in some state. That is why you must use "code splitting libraries" — they will assist you in keeping track of the chunks used. That isn't as straightforward as it appears.

React-loadable, loadable components, and react-imported-component are examples of modern React code split libraries that can do this. They will take various approaches to collect and report the chunks required for the current render call. But, no matter how they work, the end result is always the same – a single command to await all used chunks.

To actually render the page, which the user has already seen as a result of SSR(Server-side Rendering), you must load all scripts to re-render this page. To be able to render the exact same image that you can see now.

For server-side rendering, Suspense and React.lazy() are not yet available. React-loadable should still be used for server-side code splitting.

Route-based code-splitting is a method of splitting React components that involves using dynamic import() on lazy load route components. react-loadable is a higher-order component (HOC) that uses the dynamic import() syntax to load React components with promises.

Let’s understand the process with an example:

We will first create a component with the file name Home.js

import React, { Component } from "react";
class Home extends Component {
    render() {
        return (
            <div>
                <h2> Home page using Loadable</h2>
            </div>
        )
    }
}

export default Home

Now, we will import this Home Component into our App.js file.

import React from 'react';
import loadable from '@loadable/component';
const Home = loadable(() => import('./routes/Home'), {fallback: <div>Loadable...</div>});
const App = () => {
    return (
        <div>
            <Home />
        </div>
    )
}

export default App

To use @loadable/component, you have to first install it using npm install @loadable/component.

Effective React Code Splitting: A Practical Guide 

Effective React Code Splitting: A Practical Guide 

  • The component is imported with the dynamic import() syntax and assigned to the options object's loader property.
  • React-loadable also has a loading property that can be used to specify a fallback component that is rendered while the main component is loading.
  • SSR is a popular technique for rendering a client-side single-page application (SPA) on the server before sending the fully rendered page to the client. This makes it possible to serve dynamic components as static HTML markup.
  • With the help of an SSR flag that can be turned on/off, loadable components can be used for code splitting in both client and server environments.

Code-Splitting for Faster Applications

We can easily set up code-splitting inside React applications, depending on the project structure, which is useful for better-performing applications and has a positive impact on users.

React component code-splitting has never been easier with React.lazy() and React.Suspense. These features made it easier than ever to boost the performance and user experience of your React app.

Asynchronous functions help to create user-friendly applications that are efficient. However, their benefits come with some hidden costs that can manifest as bugs in your program. You now have the tools you need to break down large applications into smaller chunks and load asynchronous data while keeping the app visible to the user.

Profile

Abhresh Sugandhi

Author

Abhresh is specialized as a corporate trainer, He has a decade of experience in technical training blended with virtual webinars and instructor-led session created courses, tutorials, and articles for organizations. He is also the founder of Nikasio.com, which offers multiple services in technical training, project consulting, content development, etc.