在React JSX内部循环

2020/09/17 14:01 · javascript ·  · 0评论

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

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

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

就像您只是在调用JavaScript函数一样。您不能使用for循环来调用函数的参数:

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

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

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

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的工作方式。

不知道这是否适合您的情况,但通常使用地图是个不错的选择。

如果这是带有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>

如果您还没有map()喜欢@FakeRainBrigand的答案的数组,并且想要内联,那么源布局将比@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。

香草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(),但我并不是100%这样。)感谢@FakeRainBrigand在fill()解决方案的较早版本(请参阅修订)中纠正了我的错误

key

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

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

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

不要忘记key财产。

使用数组映射功能是React中循环遍历元素数组并根据它们创建组件的一种非常常见的方法,这是一种实现循环的好方法,这是在JSX中进行循环的一种非常有效和整洁的方法不是唯一的方法,而是首选的方法。
另外,不要忘记
根据需要为每个迭代都拥有唯一的KeyMap函数从0开始创建一个唯一索引,但是不建议使用产生的索引,但是如果您的值是唯一的或存在唯一键,则可以使用它们:

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

另外,如果您不熟悉Array上的map函数,则从MDN出发几行

map依次为数组中的每个元素调用提供的回调函数,然后从结果中构造一个新的数组。仅对具有已分配值(包括未定义)的数组索引进行调用。不会为缺少数组的元素(即从未设置的索引,已删除的索引或从未分配值的索引)调用它。

使用三个参数调用callback:元素的值,元素的索引和要遍历的Array对象。

如果将thisArg参数提供给地图,它将用作回调的this值。否则,未定义的值将用作此值。该回调最终可观察到的值是根据用于确定函数所看到的值的常规规则确定的。

map不会使调用它的数组发生变化(尽管如果调用了回调,则可能会这样做)。

如果您已经在使用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>
    );
  }
}

您还可以在return块之外提取:

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

    return (<tbody>{rows}</tbody>);
}

我知道这是一个旧线程,但是您可能想签出React模板,它确实允许您在React中使用jsx样式的模板,并带有一些指令(例如rt-repeat)。

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

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

有多种方法可以做到这一点。JSX最终会被编译为JavaScript,因此,只要您编写有效的JavaScript,就可以了。

我的回答旨在巩固此处已经介绍的所有奇妙方法:

如果没有对象数组,则只需行数:

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>
  );
}

如果您有对象数组

在该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>
      {(() => {
        const rows = [];
        for (let i = 0; i < objectRows.length; i++) {
          rows.push(<ObjectRow key={i} data={objectRows[i]} />);
        }
        return rows;
      })()}
    </tbody>
  );
}

如果numrows是一个数组,则非常简单。

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

React中的数组数据类型非常好,数组可以支持新数组,并支持过滤,缩小等。

有几个答案指向使用该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代码功能夹具这里列出

要循环的次数和回报,你可以的帮助下实现它frommap

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

哪里 i = number of times


如果您想在渲染的组件中分配唯一的密钥ID,则可以React.Children.toArray按照React文档中的建议使用

React.Children.toArray

以分配给每个子项的键的平面数组形式返回子项不透明数据结构。如果要在渲染方法中操纵子级集合,则很有用,尤其是如果要在传递它之前对this.props.children重新排序或切片。

注意:

React.Children.toArray()扁平化子级列表时,更改键以保留嵌套数组的语义。也就是说,toArray为返回的数组中的每个键添加前缀,从而使每个元素的键的作用域限定于包含它的输入数组。

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

假设我们在您的状态下有一系列商品:

[{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>

如果您选择这个转换内部回报率()渲染方法,最简单的办法是使用地图()方法。使用map()函数将数组映射为JSX语法,如下所示(使用ES6语法)。


内部父组件

<tbody>
   { objectArray.map(object => <ObjectRow key={object.id} object={object.value}>) }
</tbody>

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

警告:数组或迭代器中的每个子代都应具有唯一的“键”道具。

注意:人们经常犯的一个错误是index在迭代时将其用作键index,将元素用作键是一种反模式,您可以在此处了解更多信息简而言之,如果不是静态列表,则永远不要将其index用作键。


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

内部ObjectRow组件

const { object } = this.props

要么

const object = this.props.object

这应该获取您从父组件传递到ObjectRow组件中的变量object对象现在,您可以根据自己的目的吐出该对象中的值。


参考文献:

Javascript中的map()方法

ECMA Script 6或ES6

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>

...或者您也可以准备一个对象数组并将其映射到一个函数以获取所需的输出。我更喜欢这样做,因为它可以帮助我保持良好的编码习惯,并且在返回的渲染中没有任何逻辑。

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>
  )
}

只需用于.map()遍历您的集合并<ObjectRow>从每次迭代中返回带有道具的物品。

假设objects某处有一个数组...

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

使用地图功能+键的ES2015 Array.from

如果您什么都没有,则.map()可以使用Array.from()map函数重复元素:

<tbody>
  {Array.from({ length: 5 }, (value, key) => <ObjectRow key={key} />)}
</tbody>

我用这个:

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

PS:永远不要忘记钥匙,否则您会收到很多警告!

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

所以我可能会做类似的事情:

import _ from 'lodash';

...

const TableBody = ({ objects }) => {
  const objectRows = objects.map(obj => <ObjectRow object={obj} />);      

  return <tbody>{objectRows}</tbody>;
} 

诚然,这是非常少的代码,所以内联它可能会正常工作。

您当然可以使用其他答案建议的.map进行求解。如果您已经使用过babel,则可以考虑使用jsx-control-statements。
它们需要一些设置,但就可读性而言,这是值得的(特别是对没有反应的开发人员而言)。
如果您使用短绒棉,还有
eslint-plugin-jsx-control-statements

您的JSX代码将编译为纯JavaScript代码,所有标签都将被ReactElement对象替换在JavaScript中,不能多次调用一个函数来收集其返回的变量。

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

或者,您可以使用从JavaScript ES5开始Array.prototype.map可用的功能来处理这种情况。

也许我们可以编写其他编译器来重新创建新的JSX语法,以实现重复功能,就像Angular的ng-repeat

这可以通过多种方式来完成。

  1. 如上所述,在return将所有元素存储在数组中之前

  2. 内部循环 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>
    )

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

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

无需映射和复杂的代码。您只需要将行压入数组并返回值即可呈现它。

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

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

这是React doc的示例:JavaScript表达式为子级

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>
  );
}

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

我用它像

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

您可以执行以下操作:

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

好问题。

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

定义一个返回JSX的函数:

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

//... in JSX

<tbody>
    {myExample()}
</tbody>

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

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

           })()}
        </tbody>
本文地址:http://javascript.askforanswer.com/zaireact-jsxneibuxunhuan.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!