3

Suppose I have:

import MyComponent from "../somewhere"

I can create an instance of it by doing:

<MyComponent myprops={myprops} />

But can I create one programmatically from MyComponent and add props?


For example, I have a list of component references:

import comp1 from "somewhere"
import comp2 from "somewhere"
import comp3 from "somewhere"

var myComponents = [
    comp1, comp2, comp3
];

And now I have to take one of them and put in the view:

var randomComponent = myComponents[Math.random() * 3 | 0];

// render
render(){
    return randomComponent; // this doesn't work and certain props have to be added
}

Is there a way to avoid doing the following and achieve the same?

var myComponents = [
    <comp1 props=... />, <comp2 props=... />, <comp3 props=... />
];
Andrew Li
  • 55,805
  • 14
  • 125
  • 143
Derek 朕會功夫
  • 92,235
  • 44
  • 185
  • 247

3 Answers3

4

You can do the following:

var RandomComponent = myComponents[Math.random() * 3 | 0];

render() {
    return <RandomComponent props={foobar} />;
}

The above is demonstrated at the React Docs where the following is mentioned:

You cannot use a general expression as the React element type. If you do want to use a general expression to indicate the type of the element, just assign it to a capitalized variable first. (emphasis mine)

The reason why the component's name must be capitalized is because it will be treated as a built-in component (DOM component) if not. This works because it's just transpiled into this:

React.createElement(RandomComponent, { props: foobar });

And RandomComponent still refers to a random selected component. If randomComponent is not capitalized, you can just do it without JSX like so:

React.createElement(randomComponent, { props: foobar });

You just won't be able to do it with JSX because randomComponent is lowercase and will incidentally be transpiled into this:

React.createElement("randomComponent", { props: foobar });

Which is problematic as "randomComponent" does not refer to randomComponent.

Andrew Li
  • 55,805
  • 14
  • 125
  • 143
2

see Create react component dynamically

var component = myComponents[Math.random()*3 |0];
return React.createElement(component, props);
FuzzyTree
  • 32,014
  • 3
  • 54
  • 85
0

Thought I would share. I had a very specific use case for this using imported svg files, but I believe this would work with components as well. I wanted to have a button component that would load different svg icons given a prop type.

import LightBulb from '../my-icons/Lightbulb.svg';

const ICON_TYPES = {
  LightBulb: 'LightBulb',
};

const ICON_TYPE_FILES = {
  [ICON_TYPES.LightBulb]: LightBulb,
};

export default function IconButton({iconType}) {
  const IconComponent = ICON_TYPE_FILES[iconType];
  return (
    <Icon>
      <IconComponent />
    </Icon>
   );
};
IconButton.ICON_TYPES = ICON_TYPES

Using component:

<IconButton
  iconType={IconButton.ICON_TYPES.LightBulb}
/>
Lauren
  • 2,557
  • 1
  • 14
  • 16