React - 使用ES6模板字面量和JSX动态创建标签

5

我需要在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>

我希望能够渲染 <h2>Header 1</h2> 并且设置 name="Header 1" 以及 depth=2,但是我却得到了一个错误信息:

无法找到模块 "./HeaderComponent"

我错过了什么吗?

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

2个回答

4
也许有点晚了,但是您可以动态地创建一个组件或标签,而不使用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
引用: 当元素类型以小写字母开头时,它指的是内置组件,例如
,并导致传递给React.createElement的字符串'div'或'span'。以大写字母开头的类型,如,编译为React.createElement(Foo)并对应于在JavaScript文件中定义或导入的组件。 我们建议使用大写字母命名组件。如果您确实有一个以小写字母开头的组件,请在使用它之前将其分配给一个大写字母的变量。

如果不创建那个变量,就没有办法做到这一点,因此尝试在代码中动态执行它将无法工作(编译器限制)。

这是一个完全可行的示例:

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>


4
每个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预设不支持它。 - Marc
@user3676597(如果你不知道)babel有一个在线转译器,可以突出显示任何错误,我发现这对于这样的事情非常有用-https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-0%2Cstage-1&code= - T Mitchell
似乎没有办法在JSX中创建动态标签。现在,React.createElement似乎是唯一的方法。 - Pineda
本来就是Ben救场的;):在ReactJS中使用JSX转译器和动态元素名称- https://www.bennadel.com/blog/2917-using-dynamic-element-names-with-the-jsx-transpiler-in-reactjs.htm - Marc
@user3676597 谢谢分享,看起来你可以做到。 - T Mitchell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接