Dynamic JSX element/tag names

*爱你&永不变心* 提交于 2021-02-16 13:39:08

问题


I'm just wanted to know if there is a best practice approach to rendering an element with ReactJS dynamically

Consider these scenarios:

(1) Parameter Factory component:
A parameterised factory component whose job is to render a component based on a string parameter, is there a way of doing so without having to revert to React.createElement?

<pre><code>// The following doesn't work
class Quiz extends React.Component{
  constructor (props){
    super (props);
    this.state = {
      questionText: '',
      correctAnswer: [],
      assetType: ['DragNDrop','MultipleChoice','MatchPairs']
    }
  }
  render(){
    const { questionText, correctAnswer } = this.state;
    return <{this.state.assetType[this.props.typeIndex] />;
  }
}
</code></pre>

(2)Dynamic HTML tags:
Render a different HTML header tag based on an integer input. For this, I initially tried to use Template strings but had to resort to conditional rendering.

<pre><code>// No joy with Template strings
render (){
  <{`h${this.state.headerSize}`}>
    {this.state.headerText}
  </ {`h${this.state.headerSize}`}>
}

I like using JSX, and it would be nice to be able to use dynamic element names with it for consistency.

I'm also aware that:

assetType: ['DragNDrop','MultipleChoice','MatchPairs']

can be stored as:

assetType: [<DragNDrop />,<MultipleChoice />, <MatchPairs />]

which will work.

One issue I have with the array of JSX elements is how to store the these JSX elements in a DB? I'm guessing I'd have to store them as Strings but then how to use them when pull backed form the DB?

Can anyone suggest any working and best practice approaches to these issues?


回答1:


Regarding dynamic HTML tags:

EDIT:
As the docs suggest, Dynamic types can be used at runtime if first assign to a capitalised variable first:

class Quiz extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            questionText: '',
            correctAnswer: [],
            assetType: ['DragNDrop', 'MultipleChoice', 'MatchPairs']
        }
    }
    render() {
        const ElementNameStartsWithCapitalLetter = this.state.assetType[0];
           // ^ -- capital letter here, ensure this works when used in JSX
        return <ElementNameStartsWithCapitalLetter />;
    }
}

This is due to the fact that User Defined JSX Components Must BE Capitalized.



PREVIOUS SOLUTIONS:

Using React.createElement:

class Quiz extends React.Component{
  constructor (props){
    super (props);
    this.state = {
      questionText: '',
      correctAnswer: [],
      assetType: ['DragNDrop','MultipleChoice','MatchPairs']
    }
  }
  render(){
    const { questionText, correctAnswer } = this.state;
    {React.createElement(
      [this.props.typeIndex],
      {...questionText, ...correctAnswer}
    );}
  }
}

Using conditional rendering:

// Conditional rendering works, but yuck!
// One condition per state works
// <b>but can be unnecessarily verbose</>
getHeader() {
  switch(this.state.headerSize){
    case 1:
      return <h1>{ this.state.headerText }; <h1>
    case 2:
      return <h2>{ this.state.headerText }<h2>
    .
    .
    .
    default:
      return null;
  }
}

render (){
  return { this.getHeader() }; // bound correctly in constructor of course :)
}


来源:https://stackoverflow.com/questions/41634517/dynamic-jsx-element-tag-names

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!