8

I'm building a web app using React that shows the blueprint for the building you select, in an already selected campus.

I have a "Content" component that loads the campus or building map, depending what you chose. The "BuildingMap" component needs to load a specific blueprint according to what building you selected. It gets the props.building with the name of the building but I don't know how to load a component using that variable.

I have tried import, fetch and require but nothing seems to work.

Please help.

My code looks something like this:

//Content Component

<BuildingMap building={selectedBuilding} campus={selectedCampus} />

//BuildingMap Component

import *MyBlueprint* from (specific folder depending on the campus selected)

class BuildingMap extends React.Component {
  render(){
    return (
      <div className="blueprint" id={this.props.building}>
         {*MyBlueprint*}
      </div>
    )
  }
}
Carla Balbontin
  • 91
  • 1
  • 1
  • 7
  • Is it a requirement that you load the module at runtime as opposed to packing the components into an object and referencing them by key? The latter is far more common. – azium May 31 '17 at 21:45

3 Answers3

4

Unfortunately, you cannot import/require components dynamically in React environment.

Depending on how many buildings/blueprints there are, it's possible to import them one by one, create component-building map and pick component by building ID.

If there are many/infinite components to load, I would surely pick another method - don't know content of your problem.

import BlueprintA from './BlueprintA'
import BlueprintB from './BlueprintB'
import BlueprintC from './BlueprintC'
// ...

class BuildingMap extends React.Component {
  render(){
    const C = {
      buildingA: BlueprintA,
      buildingB: BlueprintB,
      buildingC: BlueprintC,
      // ...
    }[this.props.building]

    return (
      <div className="blueprint" id={this.props.building}>
         <C />
      </div>
    )
  }
}
Andreyco
  • 22,476
  • 5
  • 61
  • 65
  • 2
    It is *possible* to load modules dynamically, but certainly more rare for this type of circumstance, your solution is fine 99% of the time. I would also put the object construct outside of the component in case it could be used elsewhere. a good option for that could be `import * as blueprints from ..` – azium May 31 '17 at 21:51
  • Well, what I meant was it's not possible to import/require module dynamically - by value of variable, e.g. Importing all named modules is option here. Thanks for mentioning :) – Andreyco May 31 '17 at 21:58
  • It is possible to require module dynamically, though with a variable name. example: https://github.com/NCI-GDC/portal-ui/blob/relay/src/packages/%40ncigdc/theme/index.js#L16 – azium May 31 '17 at 22:32
  • Sorry for the noob question but what does this mean? ```const C = { buildingA: BlueprintA, // ... }[this.props.building]``` I don't understand the last bit, what does the [this.props.building] mean? – Miles M. Sep 23 '19 at 18:43
3

This question is pretty old but as I was looking for how to solve the same problem let me give my answer. It can be done with dynamic import React.lazy:

const OtherComponent = React.lazy(() => import('./OtherComponent'));

See more details here: https://reactjs.org/docs/code-splitting.html#reactlazy

mimic
  • 4,897
  • 7
  • 54
  • 93
2

To add to @Andreyco's answer:

Using a lookup table of string IDs/names to component classes is a typical React idiom. One common use case is a modal manager component that can render multiple different types of modals. For some examples, see Dan Abramov's answer at "How can I render a modal dialog in Redux?" (not Redux-specific), as well as some of the related articles in the React Component Patterns#Modal Dialogs and Redux Techniques#UI sections of my React/Redux links list.

Per @azium's comment: it is definitely possible to use dynamic importing (via require.ensure() or the new import() function) to load chunks at runtime, and you could add the exports from those dynamically imported chunks into a lookup table when they are loaded.

markerikson
  • 63,178
  • 10
  • 141
  • 157