DEV Community

Andrew Lee
Andrew Lee

Posted on

How to Dynamically Render Components in React

Sometimes we need to dynamically render React components. For example let's say we are building a drag and drop website builder.

Customer A wants their website to consist of Navbar2, Content1, and Footer3.

<div>
  <Navbar2 />
  <Content1 />
  <Footer3 />
</div>
Enter fullscreen mode Exit fullscreen mode

Customer B on the other hand wants a slightly different website.

<div>
  <Navbar1 />
  <Content3 />
  <Footer1 />
</div>
Enter fullscreen mode Exit fullscreen mode

If we have a lot of components, we are going to end up creating a component for every single possible combination...or we can use dynamic rendering.

First, we need a mapping of our components.

// i.e. const Navbar1 = () => <div>Navbar1</div>

const componentMapping = {
  Navbar1,
  Navbar2,
  Navbar3,
  Content1,
  Content2,
  Content3,
  Footer1,
  Footer2,
  Footer3
};
Enter fullscreen mode Exit fullscreen mode

Then we can render the website for Customer A

const customerA = ['Navbar2', 'Content1', 'Footer3'];
Enter fullscreen mode Exit fullscreen mode

and for Customer B

const customerB = ['Navbar1', 'Content3', 'Footer1'];
Enter fullscreen mode Exit fullscreen mode

with the same dynamic component.

// <Website config={customerA} />
// <Website config={customerB} />

const Website = (props) => {
  return (
    <div>
      {config.map((componentName) => {
        const Component = componentMapping[componentName];
        return <Component />;
      })}
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Latest comments (5)

Collapse
 
tsengtofu profile image
Tseng Tofu

What if the Navbar component or other component need to pass props?Is this still work?

Collapse
 
kyh profile image
Kaiyu Hsu • Edited

You could update your component list to contain the props:

const customerA = [
    { componentName: 'Navbar2', props: { foo: "bar" } },
    { componentName: 'Content1', props: {} },
    { componentName: 'Footer3', props: {} }
];
Enter fullscreen mode Exit fullscreen mode

and your renderer would look like:

const Website = ({ config }) => {
  return (
    <div>
      {config.map(({ componentName, props }) => {
        const Component = componentMapping[componentName];
        return <Component {...props} />;
      })}
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode
Collapse
 
devhammed profile image
Hammed Oyedele

Not so efficient because the components are still rendered but not in the DOM, a better option is to use function that return the component in the mapping then call the function in map callback.

Collapse
 
andyrewlee profile image
Andrew Lee

Good catch! Just noticed the typo in my componentMapping. Before it was something like

const componentMapping = {
  Navbar1: <Navbar1 />
}

I just changed it to this so we render in the map callback.

const componentMapping = {
  Navbar1
}
Collapse
 
devhammed profile image
Hammed Oyedele

Oh...I get it now.
😁😁😁