Languages
[Edit]
EN

React - import component dynamically

13 points
Created by:
AnnLen
11500

In this short article, we would like to show how to import components dynamically in React.

That kind of component attaching can be useful when:

  • we don't want to load all web application logic until some part of them is used,
  • component logic is located on a different server,
  • when we use Server Side Rendering (SSR), the attached component uses BOM (Browser Object Model, like: window, location, navigator, etc.) and┬áwe want to avoid internal problems with undefined BOM objects in compilation with NodeJS (SSR in Gatsby has problems with JS libraries that calls window, location, nagator, etc.).

Note: below example shows how to create useComponent hook that let us to load component with async import.

Quick solution (useComponent.jsx file):

import { useState } from 'react';

let componentPromise = null;
let componentModule = null;

// the method runs component import only once 
// with waiting until operation is completed for other calls
const importComponent = () => {
    if (componentModule) {
        return Promise.resolve(componentModule);
    }
    if (componentPromise) {
        return componentPromise;
    }
    componentPromise = import('/path/to/my/component') // change it to something
        .then((module) => {
            componentModule = module;
            return module;
        }));
    return componentPromise;
};

// uncomment below line to start module loading as soon as it possible
// loaded module before do not cause re-rendering / state changes later
//prepareComponent();

const useComponent = () => {
    const [component, setComponent] = useState(componentModule);
    if (component === undefined) {
        importComponent()
            .then(setComponent)    // we just wait until component is ready
            .catch(console.error); // we want to see loading exceptions in console
    }
    return component;
};

export default useComponent;

Usage example:

import React from 'react';
import useComponent from './useComponent';

const App = () => {
  const Component = useComponent();
  return (
    <div>
      {Component ? <Component.default /> : <span>Component is not imported yet!</span>}
    </div>
  );
};

export default App;

Note: change Component.default to proper export name if it is necessary.

Example import names:

static importdynamic import
import MyComponent from './my-component';const Component = useComponent();
const MyComponent = Component.default;
import {MyComponent1, MyComponent2}
from './my-component';

const Component = useComponent();
const MyComponent1 = Component.MyComponent1;
const MyComponent2 = Component.MyComponent2;

Universal component import logic

In this section we would like to show how to modify above logic to import different components indicating component paths.

import { useState } from 'react';

const statuses = { }; // keeps information about imported modules

// the method runs component import only once 
// with waiting until operation is completed for other calls
const importComponent = (path) => {
    const status = statuses[path];
    if (status.module) {
        return Promise.resolve(status.module);
    }
    if (status.promise) {
        return status.promise;
    }
    status.promise = import(path)
        .then((module) => {
            status.module = module;
            return module;
        }));
    return status.promise;
};

// uncomment below line to start module loading as soon as it possible
// loaded module before do not cause re-rendering / state changes later
//prepareComponent();

const useComponent = (path) => {
    const [component, setComponent] = useState(() => {
        const status = statuses[path];
        return status ? status.module : undefined;
    });
    if (component === undefined) {
        importComponent(path)
            .then(setComponent)    // we just wait until component is ready
            .catch(console.error); // we want to see loading exceptions in console
    }
    return component;
};

export default useComponent;

Usage example:

import React from 'react';
import useComponent from './useComponent';

const App = () => {
  const Component = useComponent('/path/to/my/component'); // change it to something
  return (
    <div>
      {Component ? <Component.default /> : <span>Component is not imported yet!</span>}
    </div>
  );
};

export default App;

Note: some transpilers resolves import('/literal/as/path/to/component/module') paths during transpilation that makes impossible to use variables with import, e.g. import(pathToMyComponentModule) - Gatsby has that. The solution for the problem is to edit the above code and replace the path with a callback that returns the import result. Finally, we should use: const Component = useComponent(() => import('/path/to/my/component'));

Native Advertising
­čÜÇ
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

ÔŁĄ´ŞĆ­čĺ╗ ­čÖé

Join