【问题标题】:React - Create tag dynamically from ES6 template literal with JSXReact - 使用 JSX 从 ES6 模板文字动态创建标签
【发布时间】:2017-05-28 15:33:34
【问题描述】:

我需要在 React render 方法中显示一个标题元素,其中级别是在构造函数中动态设置的:

class HeaderComponent extends React.Component {

    constructor(props){
        super(props);
        
        this._checkedDepth = Math.min(6, props.depth)
    }

    render(){
        return(<h{ this._checkedDepth }>{ this.props.name }</h{ this._checkedDepth }>)
    }
}

ReactDOM.render(
  <HeaderComponent name="Header 1" depth="2"/>,
  document.getElementById('app')
);
<div id="app"></div>

<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>

这应该用name="Header 1"depth=2 渲染&lt;h2&gt;Header 1&lt;/h2&gt;,但我得到一个错误:

未捕获的错误:找不到模块“./HeaderComponent”

我忽略了什么?

我正在使用React 15.4.1babel-preset-es2015 6.9.0babel-preset-react 6.5.0 并在Chrome 55 中运行它。

【问题讨论】:

    标签: reactjs babeljs template-strings


    【解决方案1】:

    可能有点太晚了,但您可以动态创建组件或标签,而无需使用 React.createClass 和 JSX 将标签名称放入变量中并像使用任何其他组件一样使用该变量。

    在您的情况下,在 render 内,您应该有类似的内容:

    const TitleTag = `h{ this._checkedDepth }>`;
    
    return <TitleTag>{ this.props.name }</TitleTag>
    

    请注意,该变量的第一个字符必须为大写,以便让 React 知道这是一个 React 组件,否则将插入一个与您的变量完全相同的名称(不是值)的标签。

    https://reactjs.org/docs/jsx-in-depth.html#user-defined-components-must-be-capitalized:

    当一个元素类型以小写字母开头时,它指的是一个 内置组件,如 &lt;div&gt;&lt;span&gt; 并生成字符串 'div''span' 传递给React.createElement。以 a 开头的类型 像&lt;Foo /&gt; 这样的大写字母编译为React.createElement(Foo) 和 对应于您的 JavaScript 文件中定义或导入的组件。

    我们建议使用大写字母命名组件。如果你有一个 以小写字母开头的组件,将其分配给 在 JSX 中使用之前大写的变量。

    如果不创建该变量,就无法做到这一点,因此尝试像在代码中那样动态地执行它是行不通的(编译器限制)。

    这是一个完整的示例:

    class HeaderComponent extends React.Component {
    
      constructor(props) {
        super(props);
        
        const depth = Math.max(Math.min(parseInt(props.depth) || 1, 6), 1);
        
        this.state = { depth };
      }
    
      onClick() {
        let depth;
        
        do {
          depth = Math.floor(Math.random() * 6) + 1;
        } while(depth === this.state.depth);
        
        this.setState({ depth });
      }
    
      render() {    
        const Title = `h${ this.state.depth }`;
      
        return <Title className="title" onClick={ () => this.onClick() }>{ this.props.name }</Title>;
      }
    }
    
    ReactDOM.render(
      <HeaderComponent name="Click Me!" depth="1"/>,
      document.getElementById('app')
    );
    body { margin: 0; }
    
    h1 { font-size: 4rem; }
    h2 { font-size: 3.5rem; }
    h3 { font-size: 3rem; }
    h4 { font-size: 2.5rem; }
    h5 { font-size: 2rem; }
    h6 { font-size: 1.5rem; }
    
    .title {
      margin: 0;
      padding: 0 .5rem;
      cursor: pointer;
      user-select: none;
    }
    
    .title:hover {
      background: #FFA;
    }
    <div id="app"></div>
    
    <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>

    【讨论】:

      【解决方案2】:

      每个 JSX 元素只是调用的语法糖 React.createElement(component, props, ...children)。所以,无论你 可以用 JSX 做也可以用纯 JavaScript 做。 - https://facebook.github.io/react/docs/react-without-jsx.html

      所以你可以这样做:

      render() {
        return React.createElement(`h${this._checkedDepth}`, this.props)
      }
      

      【讨论】:

      • 谢谢。我只是想知道我是否可以使用如图所示的 JSX 表示法,但显然 React / Babel React 预设不支持这一点。
      • @user3676597(如果你不知道的话)babel 有一个在线转译器,可以突出显示我认为对此类内容非常有用的任何错误 - babeljs.io/repl/…
      • 似乎没有办法在 JSX 中创建动态标签。 React.createElement 似乎是目前唯一的方法
      • Ben 来救援 ;):在 ReactJS 中使用带有 JSX 转译器的动态元素名称 - bennadel.com/blog/…
      • @user3676597 谢谢分享,看来你可以做到
      猜你喜欢
      • 2016-01-11
      • 2020-09-22
      • 2021-04-01
      • 2016-04-19
      • 2017-11-24
      • 2022-12-22
      • 1970-01-01
      • 2020-09-11
      相关资源
      最近更新 更多