简体   繁体   中英

Dynamic component name - React

I have three components:

const Comp0 = () => <div>1</div>;
const Comp1 = () => <div>2</div>;
const Comp2 = () => <div>3</div>;

I have also a class, with state:

state = { activeComponent: 0 }

This activeComponent can be changed by user to 1 , 2 or 0 .

In render, I have:

return (
   {React.createElement(`Comp${this.state.activeComponent}`)};
}

It should work... theoretically. However - Im getting a really weird error. Two errors.

  1. Warning: <Comp0 /> is using uppercase HTML. Always use lowercase HTML tags in React.

  2. Warning: The tag <Comp0> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.

How is that possible that they appear simultaneously?

You could simply render the dynamic tag like

const Tag = `Comp${this.state.activeComponent}`;
return (
   <Tag />
}

According to the docs :

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.

In your case it doesn't work because, you are passing the string name to React.createElement whereas for a React Component you need to pass the component like

React.createElement(Comp0);

and for a normal DOM element you would pass a string like

React.createElement('div');

and since you write

`Comp${this.state.activeComponent}`

what you get is

React.createElement('Comp0')

which isn't quite understandable to react and it throws a warning

Warning: <Comp0 /> is using uppercase HTML. Always use lowercase HTML tags in React.

You can just do a function with a mapping like this:

const stateArray = [Comp0, Comp1, Comp2];
const getComp = (Comp) => <Comp>
const getCompFromArray = (i) => getComp(stateArray[i]);

If you were to create a custom component element with React.createElement , you have to pass the direct class/function, instead of its name (that's only for DOM elements), to it, eg React.createElement(Shoot0) instead of React.createElement('Shoot0') ;

You can circumvent the issue by putting the components you intend for in array and index them

 const Shoot0 = () => <div>1</div>; const Shoot1 = () => <div>2</div>; const Shoot2 = () => <div>3</div>; const Shoots = [Shoot0, Shoot1, Shoot2]; class App extends React.Component { constructor(props) { super(props); this.state = { activeComponent: 0 }; } componentDidMount() { setInterval(() => { this.setState((prevState) => { return { activeComponent: (prevState.activeComponent + 1) % 3 } }) }, 1000) } render() { return React.createElement(Shoots[this.state.activeComponent]) } } ReactDOM.render(<App />, document.getElementById('app')) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="app"></div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM