Author avatar

Gaurav Singhal

How to Load Components Conditionally in ReactJS

Gaurav Singhal

  • Apr 6, 2020
  • 9 Min read
  • 25,401 Views
  • Apr 6, 2020
  • 9 Min read
  • 25,401 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// ...
2import AppBar from "@material-ui/core/AppBar";
3import Toolbar from "@material-ui/core/Toolbar";
4import Button from "@material-ui/core/Button";
5
6const Header = () => {
7  return (
8    <AppBar position="static">
9      <Toolbar style={{ marginLeft: "auto" }}>
10        <Button color="inherit">Home</Button>
11        <Button color="inherit">Our Services</Button>
12        <Button color="inherit">Contact Us</Button>
13        <Button color="inherit">About Us</Button>
14      </Toolbar>
15    </AppBar>
16  );
17};
18// ...
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// ...
2import MenuIcon from "@material-ui/icons/Menu";
3import IconButton from "@material-ui/core/IconButton";
4import AppBar from "@material-ui/core/AppBar";
5import Drawer from "@material-ui/core/Drawer";
6import List from "@material-ui/core/List";
7import ListItem from "@material-ui/core/ListItem";
8import ListItemText from "@material-ui/core/ListItemText";
9
10const Header = () => {
11  const [isDrawerOpen, setDrawerOpen] = useState(false);
12  return (
13    <>
14      <Drawer open={isDrawerOpen} onClose={() => setDrawerOpen(!isDrawerOpen)}>
15        <List style={{ width: 250 }}>
16          {["Home", "Our Services", "Contact Us", "About Us"].map(
17            (text, index) => (
18              <ListItem button key={text}>
19                <ListItemText primary={text} />
20              </ListItem>
21            )
22          )}
23        </List>
24      </Drawer>
25      <AppBar style={{ padding: "5px 16px" }} position="static">
26        <IconButton
27          style={{ marginRight: "auto" }}
28          color="inherit"
29          aria-label="open drawer"
30          edge="start"
31          onClick={() => setDrawerOpen(true)}
32        >
33          <MenuIcon />
34        </IconButton>
35      </AppBar>
36    </>
37  );
38};
39// ...
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.

1import React, { Component, Suspense, lazy } from "react";
2
3// ...
4
5class Header extends Component {
6  render() {
7    const isDesktop = window.innerWidth > 767;
8    if (!isDesktop) return <MobileHeader />;
9    else {
10      const DesktopHeader = lazy(() => import("./DesktopHeader"));
11      return (
12        <Suspense fallback={<MobileHeader />}>
13          <DesktopHeader />
14        </Suspense>
15      );
16    }
17  }
18}
19
20// ...
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

1import React from "react";
2import AppBar from "@material-ui/core/AppBar";
3import Toolbar from "@material-ui/core/Toolbar";
4import Button from "@material-ui/core/Button";
5
6const Header = () => {
7  return (
8    <AppBar position="static">
9      <Toolbar style={{ marginLeft: "auto" }}>
10        <Button color="inherit">Home</Button>
11        <Button color="inherit">Our Services</Button>
12        <Button color="inherit">Contact Us</Button>
13        <Button color="inherit">About Us</Button>
14      </Toolbar>
15    </AppBar>
16  );
17};
18
19export default Header;
jsx

Header/MobileHeader.js

1import React, { useState } from "react";
2import MenuIcon from "@material-ui/icons/Menu";
3import IconButton from "@material-ui/core/IconButton";
4import AppBar from "@material-ui/core/AppBar";
5import Drawer from "@material-ui/core/Drawer";
6import List from "@material-ui/core/List";
7import ListItem from "@material-ui/core/ListItem";
8import ListItemText from "@material-ui/core/ListItemText";
9
10const Header = () => {
11  const [isDrawerOpen, setDrawerOpen] = useState(false);
12  return (
13    <>
14      <Drawer open={isDrawerOpen} onClose={() => setDrawerOpen(!isDrawerOpen)}>
15        <List style={{ width: 250 }}>
16          {["Home", "Our Services", "Contact Us", "About Us"].map(
17            (text, index) => (
18              <ListItem button key={text}>
19                <ListItemText primary={text} />
20              </ListItem>
21            )
22          )}
23        </List>
24      </Drawer>
25      <AppBar style={{ padding: "5px 16px" }} position="static">
26        <IconButton
27          style={{ marginRight: "auto" }}
28          color="inherit"
29          aria-label="open drawer"
30          edge="start"
31          onClick={() => setDrawerOpen(true)}
32        >
33          <MenuIcon />
34        </IconButton>
35      </AppBar>
36    </>
37  );
38};
39
40export default Header;
jsx

Header/index.js

1import React, { Component, Suspense, lazy } from "react";
2import MobileHeader from "./MobileHeader";
3
4class Header extends Component {
5  render() {
6    const isDesktop = window.innerWidth > 767;
7    if (!isDesktop) return <MobileHeader />;
8    else {
9      const DesktopHeader = lazy(() => import("./DesktopHeader"));
10      return (
11        <Suspense fallback={<MobileHeader />}>
12          <DesktopHeader />
13        </Suspense>
14      );
15    }
16  }
17}
18
19export default Header;
jsx

App.js

1import React from "react";
2import "./styles.css";
3import Header from "./Header";
4
5export default function App() {
6  return (
7    <div className="App">
8      <Header />
9      <h1>Hello World</h1>
10    </div>
11  );
12}
jsx

index.js

1import React from "react";
2import ReactDOM from "react-dom";
3
4import App from "./App";
5
6const rootElement = document.getElementById("root");
7ReactDOM.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.