react / jsx dynamic component name

  • Last Update :
  • Techknowledgy :

For a wrapper component, a simple solution would be to just use React.createElement directly (using ES6). You could just store your component class in a variable with a name that starts with an uppercase letter. See HTML tags vs React Components. Just pass in a string value that identifies which component you want to paint, wherever you need to paint it. Decorators can be used with class components for syntactic sugar, this still requires to specify class names explicitly and register them in a map:

This is our Splunktool team suggestion ✌, we tried and its working fine
className = {
   `wrapper searchDiv ${this.state.something}`
}​

<MyComponent /> compiles to React.createElement(MyComponent, {}), which expects a string (HTML tag) or a function (ReactClass) as first parameter.

var MyComponent = Components[type + "Component"];
return
<MyComponent />;

compiles to

var MyComponent = Components[type + "Component"];
return React.createElement(MyComponent, {});

Correct:

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
    photo: PhotoStory,
    video: VideoStory
};

function Story(props) {
    // Correct! JSX type can be a capitalized variable.
    const SpecificStory = components[props.storyType];
    return <SpecificStory story={props.story} />;
}

Suggestion : 2

With React it is easy to render dynamic components utilizing JSX and React.createElement, which we can utilize to render content with specific components and layouts by only using their name. The content JSON below contains an array called body which consists of multiple objects with different fields and one attribute called component which allows us to determine what component we should use to render its actual content. We can also create an anonymous component for the case that we didn’t yet create or include a component of a specific name so we tell the user directly to create the missing component rather than throwing an exception.

1._
const data = {
   content: {
      body: [{
            _uid: "BUY6Drn9e1",
            component: "foo",
            headline: "Foo"
         },
         {
            _uid: "gJZoSLkfZV",
            component: "bar",
            title: "Bar"
         },
         {
            _uid: "X1JAfdsZxy",
            component: "foo",
            headline: "Another headline"
         }
      ]
   }
};

To allow us to render a JSON by dynamic components using their name we first have to loop through the array of components itself. Below you can see that we’re using the map function to do exactly that.

function App() {
  return (
    <div className="App">
      {data.content.body.map(block => block.component)}
    </div>
  )
}

Now to actually use the React component instead of only outputting their name we will pass the name of the component to a custom function called Components.

function App() {
  return (
    <div className="App">
      {data.content.body.map(block => Components(block))}
    </div>
  )
}

Once created we need to set-up the custom Components function we were talking about earlier. First we will create a components.js in our root folder right next to our index.js. There we will start by importing our components from the components folder itself

import React from "react";
import Foo from "./components/Foo";
import Bar from "./components/Bar";
...

Next we will define one object that maps the React components to the name we have given the components in the content JSON itself:

import React from "react";
import Foo from "./components/Foo";
import Bar from "./components/Bar";

const Components = {
   foo: Foo,
   bar: Bar
};
...

Suggestion : 3

If you're using JSX, you can simply create a variable and use that as the tag name. For example, you can create a dynamic React component name based on a condition like so: Please note that in JSX, name for React components must begin with an uppercase letter, or contain a dot in the name. This is because lowercase tag names (without a dot in the name) are interpreted as HTML tags. A JSX element is just syntactic sugar for calling React.createElement() — which has the following syntax: If you want to specify a dynamic tag name (for example, based on a condition), then you can do the following:

1._
const CustomTag = (someCondition) ? 'div' : 'Foo';

<CustomTag myProp="myValue">
   ...
</CustomTag>
2._
React.createElement(type, [props], [...children])

You can simply pass the dynamic tag name as the first argument to the React.createElement() method (as it accepts a string tag name). For example:

const type = (someCondition) ? 'div' : 'Foo';
const props = {
   myProp: 'myValue'
};

React.createElement(type, props, '...');

Suggestion : 4

Beginners often mistake generating the component name dynamically and storing it in a variable as a string. This is wrong because the first argument to the React.createElement() method can not be a plain string. JSX is the default templating language for React. It allows React developers to create a neat hierarchy of components declaratively. First, you must have components defined and created before invoking them. You cannot dynamically generate them; however, you can declaratively invoke <SomeComponent>, which can be interpreted as different components, depending on dynamic values.

For example, this is wrong:

var category = "Text";
var SomeComponent = category + "Component";
return
<SomeComponent />;
2._
export default function App() {
  const componentNames = {
    text: TextComponent,
    video: VideoComponent,
    picture: PictureComponent
  };
  var category = "text";
  var SomeComponent = componentNames[category];
  return (
    <div className="App">
      <SomeComponent />
    </div>
  );
}

function TextComponent() {
  return (
    <div>
      <h1>I am a dynamically named Text Component</h1>
    </div>
  );
}
function VideoComponent() {
  return (
    <div>
      <h1>I am a dynamically named Video Component</h1>
    </div>
  );
}
function PictureComponent() {
  return (
    <div>
      <h1>I am a dynamically named Picture Component</h1>
    </div>
  );
}

Suggestion : 5

Here is how it works. The 'type' here is an actual string under the hood, i.e. 'h1', 'h2', 'h3', etc. We just assign the 'type' to another placeholder variable called 'Component', which is then used in the JSX itself. The variable name has to start with capital letter, simply because JSX mandates that only native HTML Elements can be named starting with lowercase. We just have to assign the type (h1, h2, h3...) to a variable that starts with Capital letter (in this case, 'Component'). And bam, you can use that variable just like a Component in the return portion already. Secondly, elements that start with Capital Letter, i.e. some other React Components or some JS variables, will result in the JS object itself being passed to the React.createElement call.

In this section of the doc, it tells us 2 very important points.

Firstly, elements that start with lowercase letter, which implies any native HTML elements, e.g. div, span, h1, h2, etc. inclusive of Web Component, results in being translated to string and passed to React.createElement call.

// This Dummy component returns a 'div'
const Dummy = () => <div>Testing</div>

// It's equivalent to calling React.createElement with 'div' string
const SomeComponent = () => React.createElement('div', {}, 'Testing')

2._
// With a React component instead of raw `div`
const SomeComponent = () => <Foo>Testing</Foo>

// It's equivalent to calling React.createElement with Foo function/class
const SomeComponent = () => React.createElement(Foo, {}, 'Testing')

Supposed we want to build some typographic component that renders Headings dynamically, i.e. h1, h2, h3, h4, h5 and h6.

Drawing from the JSX explanation above, here is how we can do it.

import React, { FunctionComponent, ReactNode } from 'react';

interface Props {
  type: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
  children: ReactNode;
}

const Heading: FunctionComponent<Props> = ({
  type,
  children,
}) => {
  const Component = type;

  return (
    <Component>
      {children}
    </Component>
  )
}


Suggestion : 6

In the JSX I iterated on the menu array to show {item.icon} But then I had to change the Tailwind classes I was using depending on the responsive state of the app, for which I used the react-responsive package. using the very cool @heroicons/react package. I had to use TheIcon as React components start with an uppercase letter by convention.

1._
const menu = [
  {
    title: 'Home',
    icon: <HomeIcon className="mr-3 ml-1 h-5 w-5" /> 
  },
  { title: 'Notifications', icon: <BellIcon className="mr-3 ml-1 h-5 w-5" /> },
  { title: 'Profile', icon: <UserIcon className="mr-3 ml-1 h-5 w-5" /> },
]
2._
const menu = [
  { title: 'Home', icon: 'HomeIcon' },
  { title: 'Notifications', icon: 'BellIcon' },
  { title: 'Profile', icon: 'UserIcon' },
]

const Icon = (props) => {
  const { name } = props

  let icon = null
  if (name === 'HomeIcon') icon = HomeIcon
  if (name === 'BellIcon') icon = BellIcon
  if (name === 'UserIcon') icon = UserIcon

  return React.createElement(icon, { ...props })
}

...

<Icon name={item.icon} />
3._
const icons = {
  HomeIcon,
  BellIcon,
  UserIcon,
}

const Icon = (props) => {
  const { name } = props

  const TheIcon = icons[name]
  return <TheIcon {...props} />
}

<Icon name={item.icon} />

Suggestion : 7

Capitalized types indicate that the JSX tag is referring to a React component. These tags get compiled into a direct reference to the named variable, so if you use the JSX <Foo /> expression, Foo must be in scope. 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. This often comes up when you want to render a different component based on a prop: We recommend naming components with a capital letter. If you do have a component that starts with a lowercase letter, assign it to a capitalized variable before using it in JSX.

1._
<MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>
2._
React.createElement(
   MyButton, {
      color: 'blue',
      shadowSize: 2
   },
   'Click Me'
)
3._
<div className="sidebar" />
5._
import React from 'react';import CustomButton from './CustomButton';
function WarningButton() {
  // return React.createElement(CustomButton, {color: 'red'}, null);  return <CustomButton color="red" />;
}
6._
import React from 'react';

const MyComponents = {
  DatePicker: function DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
  }
}

function BlueDatePicker() {
  return <MyComponents.DatePicker color="blue" />;}