开发者问题收集

React JSX 中的循环

2014-04-05
2062496

我正尝试在 React JSX 中执行类似以下操作(其中 ObjectRow 是一个单独的组件):

<tbody>
    for (var i=0; i < numrows; i++) {
        <ObjectRow/>
    } 
</tbody>

我意识到并理解为什么这不是有效的 JSX,因为 JSX 映射到函数调用。但是,由于来自模板领域并且是 JSX 的新手,我不确定如何实现上述操作(多次添加组件)。

3个回答

可以将其想象成您只是在调用 JavaScript 函数。您不能在函数调用的参数所在的位置使用 for 循环:

return tbody(
    for (let i = 0; i < numrows; i++) {
        ObjectRow()
    } 
)

查看函数 tbody 如何作为参数传递给 for 循环 - 导致语法错误。

但您可以创建一个数组,然后将其作为参数传递:

const rows = [];
for (let i = 0; i < numrows; i++) {
    rows.push(ObjectRow());
}
return tbody(rows);

使用 JSX 时,您基本上可以使用相同的结构:

const rows = [];
for (let i = 0; i < numrows; i++) {
    // note: we are adding a key prop here to allow react to uniquely identify each
    // element in this array. see: https://reactjs.org/docs/lists-and-keys.html
    rows.push(<ObjectRow key={i} />);
}
return <tbody>{rows}</tbody>;

顺便说一句,我的 JavaScript 示例几乎与 JSX 示例转换后的结果完全相同。尝试使用 Babel REPL 来了解 JSX 的工作原理。

Sophie Alpert
2014-04-05

我不确定这是否适合您的情况,但通常 map 是一个很好的答案。

如果这是您使用 for 循环的代码:

<tbody>
    for (var i=0; i < objects.length; i++) {
        <ObjectRow obj={objects[i]} key={i}>
    }
</tbody>

您可以使用 map 像这样编写:

<tbody>
    {objects.map(function(object, i){
        return <ObjectRow obj={object} key={i} />;
    })}
</tbody>

ES6 语法:

<tbody>
    {objects.map((object, i) => <ObjectRow obj={object} key={i} />)}
</tbody>
Brigand
2014-04-05

如果您还没有像@FakeRainBrigand的答案那样要 map() 的数组,并且想要内联它,以便源布局与输出的对应关系比@SophieAlpert的答案更接近:

使用ES2015(ES6)语法(扩展和箭头函数)

http://plnkr.co/edit/mfqFWODVy8dKQQOkIEGV?p=preview

<tbody>
  {[...Array(10)].map((x, i) =>
    <ObjectRow key={i} />
  )}
</tbody>

回复:使用 Babel 进行转译,其 注意事项页面 中提到 Array.from 是传播所必需的,但目前( v5.8.23 )在传播实际 Array 时似乎并非如此。我有一个 文档问题 要澄清这一点。但使用风险自负或使用 polyfill。

Vanilla ES5

Array.apply

<tbody>
  {Array.apply(0, Array(10)).map(function (x, i) {
    return <ObjectRow key={i} />;
  })}
</tbody>

内联 IIFE

http://plnkr.co/edit/4kQjdTzd4w69g8Suu2hT?p=preview

<tbody>
  {(function (rows, i, len) {
    while (++i <= len) {
      rows.push(<ObjectRow key={i} />)
    }
    return rows;
  })([], 0, 10)}
</tbody>

结合其他答案中的技术

保持与输出相对应的源布局,但使内联部分更紧凑:

render: function () {
  var rows = [], i = 0, len = 10;
  while (++i <= len) rows.push(i);

  return (
    <tbody>
      {rows.map(function (i) {
        return <ObjectRow key={i} index={i} />;
      })}
    </tbody>
  );
}

使用 ES2015 语法 & Array 方法

使用 Array.prototype.fill ,您可以这样做,而不是使用如上所示的扩展:

<tbody>
  {Array(10).fill(1).map((el, i) =>
    <ObjectRow key={i} />
  )}
</tbody>

(我认为您实际上可以省略 fill() 的任何参数,但我对此并不完全确定。)感谢 @FakeRainBrigand 纠正了我在早期版本的 fill() 解决方案中的错误(请参阅修订版)。

key

在所有情况下, key 属性都会缓解开发版本的警告,但在子级中无法访问。如果您希望索引在子级中可用,则可以传递额外的属性。请参阅 列表和键 进行讨论。

JMM
2015-04-14