React Code Splitting: Boost Your Website's Speed 4x

React Code Splitting: Boost Your Website's Speed 4x

ยท

4 min read

Understanding Code Splitting: Essentially, code splitting involves rendering required components at various instances when needed. Think of code splitting as a technique that involves splitting up a larger codebase into smaller chunks to optimize performance and speed up load times

The following image provides a clear illustration of this concept.

Based on the image above, we can observe that our application has numerous features. Typically, developers would import all small and large files at the top of the main component that serves the application. However, this is inefficient as it loads unnecessary code. For instance, while on the homepage, there's no need to load the Earn page until we navigate to it. The same applies to other pages on the website

This can be achieved with the help of lazy loading in react.

๐Ÿค” What is lazy loading?

In simple terms, Lazy loading is a method used in web development to defer(stop) the loading of non-critical resources until they are needed.
From the image provided above, it is expected to load the unnecessary pages when necessary and not immediately after the App is mounted.
However... In most cases, these tasks are asynchronous. so, they tend to return promises
Apart from components, functions can be loaded lazily. (i.e Loading them only when necessary).

Let's get to see how this work!

I'd provide a code snippet for WorkWise Application whose output was used to describe lazy loading above โ˜

๐Ÿ˜• What's happening here?
Oh... Here's what I have done

  • Imported all the components required for my app to be up and running

  • Set up basic redirects using react-router-dom

  • Rendering the components as the user navigates through the app.

What everyone should think about this: Oh... I know this and this is what I am supposed to do.

Well... Yes! This could solve this problem as we do have not many lines of code to be rendered so we try our best to keep things simple. However, as the components begin to grow in file size, this method becomes way inconvenient for us

๐Ÿค” How?
Say we imported all react-icons to a file like

import * as ReactIcons from "react-icons/ai"

By close inspection, You should know that the size of this file is greater than 200kb ๐Ÿ˜ฎ.
What about the file size?
The file size is the number of storage space that a digital file takes. In our case, Let's relate it to the user's internet connection.
For a user to access the homepage, 200kb worth of data must be loaded for icons alone.
โš ๏ธ Spoiler alert: Loaded unnecessarily in most cases
Believe it's all clear now...

๐Ÿ’จ How do I get started with loading components lazily?
Like all other Hooks in React, it exports a lazy hook with others.
Also.. since it's asynchronous, it requires a loading state. React takes care of that for us by providing the Suspense tag which receives fallback as a prop. This fallback is then used as the loading message

Ok... How is it used?

  • Import the lazy hook from react

  • Import Suspense from react

  • Initialize a value to be dynamically imported

  • Wrap the initialized value as a component inside the Suspense tag in the application

  • If necessary, Add a fallback as a prop to the Suspense tag

import React, { lazy, Suspense } from "react"

const LazyComponent = lazy(() => import('./path/to/file'))

const App = () => {
    return(
        <Routes>
            <Route exact path="/" component={<Home />} />
            <Route path = "path" component={
            <Suspense fallback='<p>Loading..</p>'>
                <LazyComponent />
            </Suspense>
            }
        </Routes>
    );
}

๐Ÿ˜ฎ Congratulations! You have successfully imported a component dynamically, rendered when needed with a loading message. However, the loading message can also be another component.

โš ๏ธ Spoiler alert: The component you import dynamically must be the default export from the file.
๐Ÿฅฒ What if it is not?
If it wasn't the main function in the file, then you shouldn't export it as default as you can't have two default exports in a file.
Since it's asynchronous, it returns a promise. we can tackle the then method to force it to be set to default export.
Here's how to do that ๐Ÿ‘‡

const LazyComponentNotDefaultExport = lazy( () => import('./path/to/file').then((module) => ({default: LazyComponentNotDefaultExport  })) )

How do I do this with functions?

It's quite the same thing as components. It is easily achieved in functions than in components.
Here's a very basic example of how you can dynamically import a function to where it's needed in your app

First, we define a function that computes the sum of two numbers, another to also find the differences between two numbers

export const AddTwoNumbers = (x, y) => x + y

export const FindDifference = (x, y) => x - y


const CheckSum = async () => {
   const module = await import('./addtwo')
    alert(module.AddTwoNumbers(5, 5))
}

const App = () => {
    return (
        <button onclick={CheckSum}>5 + 5</button>
    );
}

That's all there is to it my friends.
Go try it out!
Remember to always keep things simple. You should only use it when necessary and not always so that your codebase stays readable.
And if you have enjoyed this, Please leave a like, share your thoughts in the comment section and Follow me on Twitter for more.

Did you find this article valuable?

Support Emmanuel odii by becoming a sponsor. Any amount is appreciated!

ย