使用JSX时ReactDOM呈现失败

时间:2017-05-30 07:19:14

标签: javascript reactjs react-dom

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

  

TypeError:_this2.props.children.forEach不是函数

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

// This function was based on this answer: https://stackoverflow.com/a/10734934/1650200
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')
);

1 个答案:

答案 0 :(得分:0)

在查看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
);

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