使用 JSX 时 ReactDOM 渲染失败

ReactDOM render fails when using JSX

我正在使用 ReactDOM.render() 渲染我创建的组件。由于实现的细节,该组件相当复杂,但我可以轻松呈现它 iff​​ 我避免使用 JSX 语法。但是,如果我使用 JSX,我根本无法渲染组件,并且出现以下错误:

TypeError: _this2.props.children.forEach is not a function

我的代码可以在下面看到(我也收到了一些警告,我还没有开始修复,所以你可以暂时忽略它们)。请记住,组件的 HTML 结构非常严格(由于我使用的 CSS 框架)并且无法更改。有没有一种方法可以使用 JSX 来实现相同的结果,如果可以,我做错了什么?

// This function was based on this answer: 
function generateUniqueId() {
  // always start with a letter (for DOM friendlyness)
  var idstr = String.fromCharCode(Math.floor((Math.random() * 25) + 65));
  do {
    // between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
    var ascicode = Math.floor((Math.random() * 42) + 48);
    if (ascicode < 58 || ascicode > 64) {
      // exclude all chars between : (58) and @ (64)
      idstr += String.fromCharCode(ascicode);
    }
  } while (idstr.length < 32);

  return (idstr);
}

// Technically this is not exactly a component, but I use it as such to make things simpler.
class Tab extends React.Component {
  render() {
    return React.createElement('div', {}, this.props.children);
  }
}

// This is my Tabs component
class Tabs extends React.Component {
  // In the constructor, I take all children passed to the component
  // and push them to state with the necessary changes made to them.
  constructor(props) {
    super(props);
    var state = {
      group: 'tab_group_' + generateUniqueId(),
      children: []
    }
    this.props.children.forEach(
      function(child) {
        if (!child instanceof Tab) {
          throw "All children of a 'Tabs' component need to be of type 'Tab'. Expected type: 'Tab' Found Type: '" + child.class + "'";
          return;
        }
        var tab = Object.assign({}, child);
        tab.internalId = 'tab_' + generateUniqueId();
        state.children.push(tab);
      }
    );
    this.state = state;
  }
  // When rendering, I don't render the children as needed, but I create
  // the structure I need to use for the final result.
  render() {
    var childrenToRender = [];
    var groupName = this.state.group;
    this.state.children.forEach(function(tab) {
      childrenToRender.push(
        React.createElement(
          'input', {
            type: 'radio',
            name: groupName,
            id: tab.internalId,
            checked: true,
            'aria-hidden': 'true'
          }
        )
      );
      childrenToRender.push(
        React.createElement(
          'label', {
            'htmlFor': tab.internalId,
            'aria-hidden': 'true'
          },
          'demo-tab'
        )
      );
      childrenToRender.push(React.createElement('div', {}, tab.props.children));
    });
    return React.createElement('div', {
      'className': 'tabs'
    }, childrenToRender);
  }
}

// This works fine
ReactDOM.render(
  React.createElement(Tabs, {}, [React.createElement(Tab, {}, 'Hello world')]),
  document.getElementById('root')
);

// This fails with the error mentioned above
// ReactDOM.render(
//  <Tabs>
//   <Tab>Hello, world!</Tab>
//  </Tabs>,
//  document.getElementById('root')
// );
<link rel="stylesheet" href="https://gitcdn.link/repo/Chalarangelo/mini.css/master/dist/mini-default.min.css">
<script src="https://unpkg.com/react@latest/dist/react.js"></script>
<script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
<div id="root"></div>

更新: 由于处理方式的原因,只有当我实际上只将一个 <Tab> 传递给 <Tabs> 时才会发生这种情况。例如,如果我使用以下代码,我可以使用 JSX 来渲染组件及其内容:

ReactDOM.render(
    <Tabs>
        <Tab>Hello, world!</Tab>
        <Tab>Hello, world!</Tab>
    </Tabs>,
    document.getElementById('root')
);

在检查了 JSX 代码的 babel 输出后,我意识到它没有输出类似 [React.createElement(Tab, {}, 'Hello world')] 的东西,而是更像 React.createElement(Tab, {}, 'Hello world') 的东西,这意味着它不是一个数组,从而导致 .forEach().

出现问题

对于任何感兴趣的人,我所做的是检查 this.props.children 是否是一个数组,如果不是,则将其实际转换为一个数组。示例如下:

if (!Array.isArray(this.props.children))
    var tempProps = [this.props.children];
else
    var tempProps = this.props.children;
tempProps.forEach(
    // Rest of the code is pretty much the same as before
);

这不是一个非常优雅的解决方案,所以如果您知道任何更优雅的答案,请随时post。