Loading React Components Dynamically on Demand

featured
December 04, 2017
💫 Originally posted here. Broken? Let me know ~

*UPDATE* – October 28, 2018

Refer to the updated post, Loading React Components Dynamically on Demand using React.lazy if you are using v16.6.0+.


I was looking for implementations for a Factory Pattern in JavaScript to get rid of a switch statement when displaying React components.

Then I ran into a dynamic import().

I will show you 3 ways to use import() to dynamically load React Components.

  1. Loading React Components DynamicallyDemoSource Code
  2. Handling Different Data TypesDemoSource Code
  3. Loading Components on DemandDemoSource Code

Let’s dive in 🏊~

Case 1 – Loading React Components Dynamically

Problem

Suppose that you want to display differently for each event in an events array.

Within IfApp.render(), one would use a if/switch statement to check what type of event it is and create a component as shown below.

There are two issues with this approach.

  1. it quickly becomes a maintenance nightmare as new event gets created.
  2. We are importing components even if we don’t need it

Alternative Approach

We can mitigate the problem if

  1. We can import dynamically only the components we need, and
  2. also make it easier to maintain by getting rid of switch statement.

I will use import() statement to dynamically load event component (Please refer to this excellent article by Serg Hospodarets for  import() ).

Here is the demo code structure.

 

 

 

Here is the method to add a component by type name (“PushEvent”, “ReleaseEvent”, and “StatusEvent”).

Given a type name, addComponent() imports a component file and adds it to this.state.components.

And also, if an unknown type is passed, it displays an error message in console.

And the method is called for each type within componentDidMount().

We render imported components as shown below.

Note that you need to have a unique key for each Component object instance, so I used shortid to generate unique key for each component.

The full source for App component is shown below.

Now the switch statement within render() is gone and App doesn’t need to change when a new type is added (refer to Open-Close Principle). When a new type is added, we just need to create a new component under components folder.

And also, scripts get loaded dynamically as shown in the video below.

Live Demo on Netlify

Case 2 – Handling Different Data Types

Let’s take a look at more advanced scenario. Now each type is associated with data having different schema.

It’s from an actual response from a public GitHub API call.

There are 37 types of events, which one having slightly different response schema.

As it was the case in the Case 1, we could simply create an GitHub event handler component and let each one deal with different type of payload data.

First, the code structure looks like this.

 

 

 

 

 

 

 

 

We pass the JSON response to GitHubEventApp like following.

Then we load components for each event in componentDidMount().

Two things are worth mentioning here;

  1. I am instantiating Component within this.setState. It is because to make component sorting easier later in render()(I’d appreciate it if anyone let me know instantiating here instead of in render() would cause a performance issue or not).
  2. I am passing all event properties while instantiating a component (Each dynamically imported components can pick and choose props to use).

Now let’s render the result in descending order (higher the ID, the later the event was created).

Here is the glorious result 🎉🎉🎉 (Please pardon the appearance…)

You can see that each event are rendered differently.

Component codes are listed here for the sake of completeness.

Live Demo on Netlify

ForkEvent.js

NullEvent.js

PushEvent.js

WatchEvent.js

 

Case 3 – Loading Components on Demand

The last case is when we want to display different views for the same input.

Suppose that given data, you can show it as a tabular form or as a graph.

Code structure looks like this.

 

 

 

 

 

 

 

 

Here is the shared data we want to display in tabular and/or graph representations.

Here is how the result looks before digging into the implementation (Please pardon my CSS skills again).

 

Live Demo on Netlify

App component initializes state with following properties.

  1. loadedComponents tracks what components have been added as not to load more than once.
  2. components holds view components (tabular or graph).

render() simply has 3 buttons and handles the click event.

Each onClick events handlers adds a different view.

addView imports a new view component by view name.

Here are the views components.

TableView.js – Formats data using HTML table.

GraphView.js – Formats data graphically.

NullView.js – Does nothing.

Parting Words

I’ve discussed three cases.

  1. Loading React Components DynamicallyDemoSource Code
  2. Handling Different Data TypesDemoSource Code
  3. Loading Components on DemandDemoSource Code

I’d appreciate it if you can point out any optimizations or improvements I can make.