Author avatar

Gaurav Singhal

How to Load Components Conditionally in ReactJS

Gaurav Singhal

  • Apr 6, 2020
  • 9 Min read
  • 1,784 Views
  • Apr 6, 2020
  • 9 Min read
  • 1,784 Views
Web Development
Front End Web Development
Client-side Framework
React

Introduction

In this guide, you'll learn how to optimize React applications by loading components conditionally, or only when they are required. The concept of loading components dynamically during runtime is called lazy loading. It's a straightforward concept: Do not render components if they are not viewed or needed at the moment.

Use Case

Suppose you are working on a web app that needs to be mobile friendly and follow a mobile-first design concept. On mobile, the header must use drawer navigation, and on desktop, it can be a default navigation bar like in most websites. You can create a responsive header, but it will increase the bundle size since it will have the code for both drawer navigation and a navigation bar.

Think of it this way: Your mobile version of the app does not need to know about the desktop version's header. That's where lazy loading comes into the picture.

Start with Creating the Headers

Create a folder called "Header" in the root of your project. Inside the folder, create two component files, MobileHeader.js and DeskopHeader.js.

Please note that this guide uses the material-ui library to prettify the UI, but you can use any other library of your choice.

Inside the DesktopHeader.js file, create an <AppBar /> with your navigation links.

Import AppBar, Toolbar, and Button from the material-ui library.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ...
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import Button from "@material-ui/core/Button";

const Header = () => {
  return (
    <AppBar position="static">
      <Toolbar style={{ marginLeft: "auto" }}>
        <Button color="inherit">Home</Button>
        <Button color="inherit">Our Services</Button>
        <Button color="inherit">Contact Us</Button>
        <Button color="inherit">About Us</Button>
      </Toolbar>
    </AppBar>
  );
};
// ...
jsx

In the MobileHeader.js file, import the Drawer and List components to create the drawer navigation. Use the useState hook to control the drawer behavior.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// ...
import MenuIcon from "@material-ui/icons/Menu";
import IconButton from "@material-ui/core/IconButton";
import AppBar from "@material-ui/core/AppBar";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";

const Header = () => {
  const [isDrawerOpen, setDrawerOpen] = useState(false);
  return (
    <>
      <Drawer open={isDrawerOpen} onClose={() => setDrawerOpen(!isDrawerOpen)}>
        <List style={{ width: 250 }}>
          {["Home", "Our Services", "Contact Us", "About Us"].map(
            (text, index) => (
              <ListItem button key={text}>
                <ListItemText primary={text} />
              </ListItem>
            )
          )}
        </List>
      </Drawer>
      <AppBar style={{ padding: "5px 16px" }} position="static">
        <IconButton
          style={{ marginRight: "auto" }}
          color="inherit"
          aria-label="open drawer"
          edge="start"
          onClick={() => setDrawerOpen(true)}
        >
          <MenuIcon />
        </IconButton>
      </AppBar>
    </>
  );
};
// ...
jsx

Lazy Loading <DesktopHeader /> Component

Next, inside the Header folder, create an index.js file. This file will have the magical code to load the component conditionally.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React, { Component, Suspense, lazy } from "react";

// ...

class Header extends Component {
  render() {
    const isDesktop = window.innerWidth > 767;
    if (!isDesktop) return <MobileHeader />;
    else {
      const DesktopHeader = lazy(() => import("./DesktopHeader"));
      return (
        <Suspense fallback={<MobileHeader />}>
          <DesktopHeader />
        </Suspense>
      );
    }
  }
}

// ...
jsx

That's pretty much all you need.

The lazy() function creates the component that is loaded using the dynamic import() function. It accepts a function as its argument and returns a promise to load the component. But components that are created using the lazy() function only get loaded when they need to be rendered.

Therefore, you need to display some sort of a placeholder or loading indicator until the components get loaded. That's where the <Suspense /> component comes into the picture. The <Suspense /> component is meant for wrapping lazy components created by the lazy() function.

The above code first checks whether the user is on a desktop or not by using the window.innerWidth property. That determines which header to render. If it is a desktop device, you need to lazy load it before rendering. As a fallback for the desktop header, the <MobileHeader /> component is rendered just in case something goes wrong and the <DesktopeHeader /> component does not load.

Complete Source Code

Check out the entire source code in this section.

Header/DesktopHeader.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from "react";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import Button from "@material-ui/core/Button";

const Header = () => {
  return (
    <AppBar position="static">
      <Toolbar style={{ marginLeft: "auto" }}>
        <Button color="inherit">Home</Button>
        <Button color="inherit">Our Services</Button>
        <Button color="inherit">Contact Us</Button>
        <Button color="inherit">About Us</Button>
      </Toolbar>
    </AppBar>
  );
};

export default Header;
jsx

Header/MobileHeader.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import React, { useState } from "react";
import MenuIcon from "@material-ui/icons/Menu";
import IconButton from "@material-ui/core/IconButton";
import AppBar from "@material-ui/core/AppBar";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";

const Header = () => {
  const [isDrawerOpen, setDrawerOpen] = useState(false);
  return (
    <>
      <Drawer open={isDrawerOpen} onClose={() => setDrawerOpen(!isDrawerOpen)}>
        <List style={{ width: 250 }}>
          {["Home", "Our Services", "Contact Us", "About Us"].map(
            (text, index) => (
              <ListItem button key={text}>
                <ListItemText primary={text} />
              </ListItem>
            )
          )}
        </List>
      </Drawer>
      <AppBar style={{ padding: "5px 16px" }} position="static">
        <IconButton
          style={{ marginRight: "auto" }}
          color="inherit"
          aria-label="open drawer"
          edge="start"
          onClick={() => setDrawerOpen(true)}
        >
          <MenuIcon />
        </IconButton>
      </AppBar>
    </>
  );
};

export default Header;
jsx

Header/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React, { Component, Suspense, lazy } from "react";
import MobileHeader from "./MobileHeader";

class Header extends Component {
  render() {
    const isDesktop = window.innerWidth > 767;
    if (!isDesktop) return <MobileHeader />;
    else {
      const DesktopHeader = lazy(() => import("./DesktopHeader"));
      return (
        <Suspense fallback={<MobileHeader />}>
          <DesktopHeader />
        </Suspense>
      );
    }
  }
}

export default Header;
jsx

App.js

1
2
3
4
5
6
7
8
9
10
11
12
import React from "react";
import "./styles.css";
import Header from "./Header";

export default function App() {
  return (
    <div className="App">
      <Header />
      <h1>Hello World</h1>
    </div>
  );
}
jsx

index.js

1
2
3
4
5
6
7
import React from "react";
import ReactDOM from "react-dom";

import App from "./App";

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
jsx

Conclusion

The lazy() function and the <Suspense /> component have made it easy for developers to load components conditionally. Lazy loading components will help you enhance the overall user experience and make your application mobile-friendly. This is important considering that more than half of all web traffic comes via mobile devices, many of which are mid-tier or low-end devices.

6