首页 文章

在React JSX中循环

提问于
浏览
834

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

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

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

30 回答

  • 11

    您还可以在返回块之外提取:

    render: function() {
        var rows = [];
        for (var i = 0; i < numrows; i++) {
            rows.push(<ObjectRow key={i}/>);
        } 
    
        return (<tbody>{rows}</tbody>);
    }
    
  • 5

    由于您在JSX代码中编写Javascript语法,因此需要将Javascript包装在花括号中 .

    row = () => {
       var rows = [];
       for (let i = 0; i<numrows; i++) {
           rows.push(<ObjectRow/>);
       }
       return rows;
    }
    <tbody>
    {this.row()}  
    </tbody>
    
  • 696

    如果你还没有像@FakeRainBrig和_78345的回答那样的数组 map()

    使用ES2015(ES6)语法(扩展和箭头功能)

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

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

    Re:与Babel一起转发,它的caveats page表示传播需要 Array.from ,但目前( v5.8.23 )在传播实际的 Array 时似乎并非如此 . 我有一个documentation issue公开澄清这一点 . 但请自担风险或使用polyfill .

    香草ES5

    Array.apply

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

    Inline 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.prototype.fill ,您可以将此作为使用传播的替代方法,如上所示:

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

    (我认为你实际上可以省略 fill() 的任何参数,但我不是100% . )感谢@FakeRainBrigand在早期版本的 fill() 解决方案中纠正我的错误(参见修订版) .

    在所有情况下, key attr都会缓解开发构建的警告,但在子级中无法访问 . 如果您希望子项中的索引可用,则可以传递额外的attr . 有关讨论,请参见Lists and Keys .

  • 9

    ES2015 / Babel的可能性是使用生成器函数来创建JSX数组:

    function* jsxLoop(times, callback)
    {
        for(var i = 0; i < times; ++i)
            yield callback(i);
    }
    
    ...
    
    <tbody>
        {[...jsxLoop(numrows, i =>
            <ObjectRow key={i}/>
        )]}
    </tbody>
    
  • 4

    我用这个:

    gridItems = this.state.applications.map(app =>
                                <ApplicationItem key={app.Id} app={app } />
                                );
    

    PD:永远不要忘记密钥,否则你会收到很多警告!

  • 21

    这可以通过多种方式完成 .

    • 如上所述,在 return 之前存储数组中的所有元素

    • 循环 return

    方法1

    let container =[];
        let arr = [1,2,3] //can be anything array, object 
    
        arr.forEach((val,index)=>{
          container.push(<div key={index}>
                         val
                         </div>)
            /** 
            * 1. All loop generated elements require a key 
            * 2. only one parent element can be placed in Array
            * e.g. container.push(<div key={index}>
                                        val
                                  </div>
                                  <div>
                                  this will throw error
                                  </div>  
                                )
            **/   
        });
        return (
          <div>
             <div>any things goes here</div>
             <div>{container}</div>
          </div>
        )
    

    方法2

    return(
         <div>
         <div>any things goes here</div>
         <div>
            {(()=>{
              let container =[];
              let arr = [1,2,3] //can be anything array, object 
              arr.forEach((val,index)=>{
                container.push(<div key={index}>
                               val
                               </div>)
                             });
                        return container;     
            })()}
    
         </div>
      </div>
    )
    
  • 6

    让我们说你们州有一系列物品:

    [{name: "item1", id: 1}, {name: "item2", id: 2}, {name: "item3", id: 3}]
    
    <tbody>
        {this.state.items.map((item) => {
            <ObjectRow key={item.id} name={item.name} />
        })} 
    </tbody>
    
  • 848

    不确定这是否适用于您的情况,但通常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>
    
  • 9

    这是一个简单的解决方案 .

    var Object_rows=[];
    for (var i=0; i < numrows; i++) {
        Object_rows.push(<ObjectRow/>)
    } 
    <tbody>
    {Object_rows}
    </tbody>
    

    不需要映射和复杂的代码 . 您只需要将行推送到数组并返回值以呈现它 .

  • 57

    ES2015带有map功能键的Array.from

    如果你没有任何东西 .map() 你可以使用 Array.from()mapFn 重复元素:

    <tbody>
      {Array.from({ length: 5 }, (v, k) => <ObjectRow key={k} />)}
    </tbody>
    
  • 11

    您当然可以使用.map解决,如其他答案所示 . 如果你已经使用了babel,你可以考虑使用jsx-control-statements它们需要一点设置,但我认为's worth in terms of readability (especially for non-react developer). If you use a linter, there'也是eslint-plugin-jsx-control-statements

  • 10

    我倾向于采用编程逻辑发生在 render 的返回值之外的方法 . 这有助于保持实际呈现的内容易于理解 .

    所以我可能会这样做:

    import _ from 'lodash';
    
    ...
    
    const TableBody = ({ objects }) => {
      const objectRows = objects.map(obj => <ObjectRow object={obj} />);      
    
      return <tbody>{objectRows}</tbody>;
    }
    

    不可否认,这是一个很少的代码,内联它可能会正常工作 .

  • 12

    使用 Array map 函数是循环 Array 元素并在 React 中根据它们创建组件的非常常见的方法,这是一个很好的方法来做一个循环,这是非常有效和整洁的方式在 JSX 做你的循环,这是 not 唯一的方法要做到这一点,但 preferred way.

    另外,不要忘记根据需要为每次迭代设置 unique Key . Map函数从0创建一个唯一索引,但不建议使用producd索引,但如果您的值是唯一的,或者如果有唯一键,则可以使用它们:

    <tbody>
      {numrows.map(x=> <ObjectRow key={x.id} />)}
    </tbody>
    

    如果您不熟悉Array上的map函数,那么来自 MDN 的行也很少:

    map按顺序为数组中的每个元素调用一次提供的回调函数,并从结果中构造一个新数组 . 仅对已分配值的数组的索引(包括undefined)调用回调 . 它不会被调用缺少数组的元素(即,从未设置过的索引,已删除的索引或从未赋值的索引) . 使用三个参数调用回调:元素的值,元素的索引和要遍历的Array对象 . 如果提供thisArg参数进行映射,则它将用作回调的此值 . 否则,undefined值将用作其值 . 回调最终可观察到的该值根据用于确定函数所见的通常规则来确定 . map不会改变调用它的数组(尽管回调,如果被调用,可能会这样做) .

  • 11

    可以想象你're just calling JavaScript functions. You can'在一个函数中放置一个 for 循环呼叫:

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

    但你可以创建一个数组,然后将其传递给:

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

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

    var rows = [];
    for (var i = 0; i < numrows; i++) {
        // note: we add 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的工作原理 .

  • 16

    如果你已经在使用lodash,_.times函数很方便 .

    import React, { Component } from 'react';
    import Select from './Select';
    import _ from 'lodash';
    
    export default class App extends Component {
        render() {
            return (
                <div className="container">
                    <ol>
                        {_.times(3, i =>
                            <li key={i}>
                                <Select onSelect={this.onSelect}>
                                    <option value="1">bacon</option>
                                    <option value="2">cheez</option>
                                </Select>
                            </li>
                        )}
                    </ol>
                </div>
            );
        }
    }
    
  • 11

    我知道这是一个旧线程,但是你可能想要签出http://wix.github.io/react-templates/,它允许你在反应中使用jsx风格的模板,带有一些指令(例如rt-repeat) .

    您的示例,如果您使用react-templates,将是:

    <tbody>
         <ObjectRow rt-repeat="obj in objects"/>
    </tbody>
    
  • 8

    好问题 .

    当我想添加一定数量的组件时,我所做的就是使用辅助函数 .

    定义一个返回JSX的函数:

    const myExample = () => {
        let myArray = []
        for(let i = 0; i<5;i++) {
            myArray.push(<MyComponent/>)
        }
        return myArray
    }
    
    //... in JSX
    
    <tbody>
        {myExample()}
    </tbody>
    
  • 6

    要循环多次并返回,您可以在frommap的帮助下实现它:

    <tbody>
        {
          Array.from(Array(i)).map(() => <ObjectRow />)
        }
      </tbody>
    

    哪里 i = number of times

  • 5

    你可以这样做:

    let foo = [1,undefined,3]
    { foo.map(e => !!e ? <Object /> : null )}
    
  • 5

    如果numrows是一个数组,那很简单 .

    <tbody>
       {numrows.map(item => <ObjectRow />)}
    </tbody>
    

    React中的数组数据类型非常好,数组可以支持新数组,并支持过滤,减少等 .

  • 341

    有几个答案指向使用 map 语句 . 下面是一个完整的示例,它使用 FeatureList 组件中的迭代器来基于名为 features 的JSON数据结构列出 Feature 组件 .

    const FeatureList = ({ features, onClickFeature, onClickLikes }) => (
      <div className="feature-list">
        {features.map(feature =>
          <Feature
            key={feature.id}
            {...feature}
            onClickFeature={() => onClickFeature(feature.id)}
            onClickLikes={() => onClickLikes(feature.id)}
          />
        )}
      </div>
    );
    

    您可以在GitHub上查看完整的FeatureList code . features fixture is listed here .

  • 51

    ...或者您也可以准备一个对象数组并将其映射到一个函数以获得所需的输出 . 我更喜欢这个,因为它有助于我保持编码的良好实践,在渲染的返回中没有逻辑 .

    render() {
    const mapItem = [];
    for(let i =0;i<item.length;i++) 
      mapItem.push(i);
    const singleItem => (item, index) {
     // item the single item in the array 
     // the index of the item in the array
     // can implement any logic here
     return (
      <ObjectRow/>
    )
    
    }
      return(
       <tbody>{mapItem.map(singleItem)}</tbody>
      )
    }
    
  • 17

    以下是来自React doc的示例:https://facebook.github.io/react/docs/jsx-in-depth.html#javascript-expressions-as-children

    function Item(props) {
      return <li>{props.message}</li>;
    }
    
    function TodoList() {
      const todos = ['finish doc', 'submit pr', 'nag dan to review'];
      return (
        <ul>
          {todos.map((message) => <Item key={message} message={message} />)}
        </ul>
      );
    }
    

    根据你的情况,我建议像这样写:

    function render() {
      return (
        <tbody>
          {numrows.map((roe, index) => <ObjectRow key={index} />)}
        </tbody>
      );
    }
    

    请注意Key非常重要,因为React使用Key来区分数组中的数据 .

  • 28

    如果您选择在 render render 方法内转换此方法,则最简单的选项是使用 map( ) 方法 . 使用map()函数将数组映射到JSX语法,如下所示(使用ES6语法) .


    Inside parent component

    <tbody> { objectArray.map((object, index) => <ObjectRow key={index} object={object}>) } </tbody>

    请注意 key 属性已添加到您的子组件 . 如果未提供键属性,则可以在控制台上看到以下警告 .

    警告:数组或迭代器中的每个子节点都应该具有唯一的“键”支柱 .


    现在在 ObjectRow 组件中,您可以从其属性访问该对象 .

    Inside ObjectRow component

    const { object } = this.props

    要么

    const object = this.props.object

    这应该会将您从父组件传递的对象提取到 ObjectRow 组件中的变量 object . 现在,您可以根据目的吐出该对象中的值 .


    参考文献:

    map() method in Javascript

    ECMA Script 6 or ES6

  • 7

    我喜欢它

    <tbody>
    { numrows ? (
       numrows.map(obj => { return <ObjectRow /> }) 
    ) : null}
    </tbody>
    
  • 36

    只需使用 .map() 循环遍历您的集合,并使用每次迭代的道具返回 <ObjectRow> 项 .

    假设 objects 是某个地方的数组......

    <tbody>
      { objects.map((obj, index) => <ObjectRow obj={ obj } key={ index }/> ) }
    </tbody>
    
  • 4

    有很多方法可以做到这一点 . JSX最终被编译为JavaScript,所以只要你编写有效的JavaScript,你就会很好 .

    我的回答旨在巩固已经呈现的所有精彩方式:

    If you do not have an array of object, simply the number of rows:

    return 块内,创建 Array 并使用 Array.prototype.map

    render() {
      return (
        <tbody>
          {Array(numrows).fill(null).map((value, index) => (
            <ObjectRow key={index}>
          ))}
        </tbody>
      );
    }
    

    return 块之外,只需使用普通的JavaScript for循环:

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

    立即调用函数表达式:

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

    If you have an array of objects

    return 块中, .map() 每个对象为 <ObjectRow> 组件:

    render() {
      return (
        <tbody>
          {objectRows.map((row, index) => (
            <ObjectRow key={index} data={row} />
          ))}
        </tbody>
      );
    }
    

    return 块之外,只需使用普通的JavaScript for循环:

    render() {
      let rows = [];
      for (let i = 0; i < objectRows.length; i++) {
        rows.push(<ObjectRow key={i} data={objectRows[i]} />);
      } 
      return (
        <tbody>{rows}</tbody>
      );
    }
    

    立即调用函数表达式:

    render() {
      return (
        <tbody>
          {(() => {
            let rows = [];
            for (let i = 0; i < objectRows.length; i++) {
              rows.push(<ObjectRow key={i} data={objectRows[i]} />);
            }
            return rows;
          })()}
        </tbody>
      );
    }
    
  • 9

    您还可以使用自调用功能:

    return <tbody>
               {(() => {
                  let row = []
                  for (var i = 0; i < numrows; i++) {
                      row.push(<ObjectRow key={i} />)
                  }
                  return row
    
               })()}
            </tbody>
    
  • 9

    您的JSX代码将编译为纯JavaScript代码,任何标记都将被 ReactElement 对象替换 . 在JavaScript中,您无法多次调用函数来收集返回的变量 .

    这是非法的,唯一的方法是使用数组来存储返回变量的函数 .

    或者您可以使用Array.prototype.map(可用since JavaScript ES5)来处理这种情况 .

    也许我们可以编写其他编译器来重新创建一个新的JSX语法来实现重复函数,就像Angular's ng-repeat一样 .

  • 8

    只需使用带有ES6语法的 map Array方法:

    <tbody>
      {items.map(item => <ObjectRow key={item.id} name={item.name} />)} 
    </tbody>
    

    不要忘记 key 属性 .

相关问题