我正在React中尝试做类似以下的事情JSX
(其中ObjectRow是一个单独的组件):
<tbody>
for (var i=0; i < numrows; i++) {
<ObjectRow/>
}
</tbody>
我意识到并理解为什么这是无效的JSX
,因为它JSX
映射到函数调用。但是,由于来自模板领域并且是的新手JSX
,所以我不确定如何实现上述目标(多次添加组件)。
我正在React中尝试做类似以下的事情JSX
(其中ObjectRow是一个单独的组件):
<tbody>
for (var i=0; i < numrows; i++) {
<ObjectRow/>
}
</tbody>
我意识到并理解为什么这是无效的JSX
,因为它JSX
映射到函数调用。但是,由于来自模板领域并且是的新手JSX
,所以我不确定如何实现上述目标(多次添加组件)。
您还可以使用自调用功能:
return <tbody>
{(() => {
let row = []
for (var i = 0; i < numrows; i++) {
row.push(<ObjectRow key={i} />)
}
return row
})()}
</tbody>
您可以执行以下操作:
let foo = [1,undefined,3]
{ foo.map(e => !!e ? <Object /> : null )}
我用它像
<tbody>
{ numrows ? (
numrows.map(obj => { return <ObjectRow /> })
) : null
}
</tbody>
由于您是在JSX代码中编写Javascript语法,因此需要将Javascript括在花括号中。
row = () => {
var rows = [];
for (let i = 0; i<numrows; i++) {
rows.push(<ObjectRow/>);
}
return rows;
}
<tbody>
{this.row()}
</tbody>
这是一个简单的解决方案。
var Object_rows=[];
for (var i=0; i < numrows; i++) {
Object_rows.push(<ObjectRow/>)
}
<tbody>
{Object_rows}
</tbody>
无需映射和复杂的代码。您只需要将行压入数组并返回值即可进行渲染。
这可以通过多种方式来完成。
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>
)
方法二
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>
)
您的JSX代码将编译为纯JavaScript代码,所有标签都将被ReactElement
对象替换。在JavaScript中,不能多次调用函数来收集其返回的变量。
这是非法的,唯一的方法是使用数组存储函数返回的变量。
或者,您可以使用从JavaScript ES5开始Array.prototype.map
可用的版本来处理这种情况。
也许我们可以编写其他编译器来重新创建新的JSX语法,以实现重复功能,就像Angular的ng-repeat
。
您当然可以使用其他答案建议的.map进行求解。如果您已经使用过babel,则可以考虑使用jsx-control-statements。 它们需要一些设置,但就可读性而言,这是值得的(特别是对没有反应的开发人员而言)。如果您使用短绒棉,则还有eslint-plugin-jsx-control-statements
如果没有什么.map()
可以使用Array.from()
的map
函数来重复元素:
<tbody>
{Array.from({ length: 5 }, (value, key) => <ObjectRow key={key} />)}
</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>
我用这个:
gridItems = this.state.applications.map(app =>
<ApplicationItem key={app.Id} app={app } />
);
PD:永远不要忘记钥匙,否则您会收到很多警告!
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>
如果您选择这个转换内部回报率()的渲染方法,最简单的办法是使用地图()方法。使用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
的对象。现在,您可以根据自己的目的吐出该对象中的值。
参考文献:
假设我们在您的状态下有一系列商品:
[{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>
如果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代码。该功能夹具这里列出。
To loop for a number of times and return, you can achieve it with the help of from
and map
:
<tbody>
{
Array.from(Array(i)).map(() => <ObjectRow />)
}
</tbody>
where i = number of times
If you want to assign unique key IDs into the rendered components, you can use React.Children.toArray
as proposed in the React documentation
React.Children.toArray
以分配给每个子项的键的平面数组形式返回子项不透明数据结构。如果要在渲染方法中操纵子级集合,则很有用,尤其是如果要在传递它之前对this.props.children重新排序或切片。
注意:
React.Children.toArray()
展平子列表时,更改键以保留嵌套数组的语义。也就是说,toArray为返回的数组中的每个键添加前缀,以便每个元素的键的作用域限定于包含它的输入数组。
<tbody>
{
React.Children.toArray(
Array.from(Array(i)).map(() => <ObjectRow />)
)
}
</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>
);
}
您也可以在return块之外提取:
render: function() {
var rows = [];
for (var i = 0; i < numrows; i++) {
rows.push(<ObjectRow key={i}/>);
}
return (<tbody>{rows}</tbody>);
}
只需使用具有ES6语法的map Array方法即可:
<tbody>
{items.map(item => <ObjectRow key={item.id} name={item.name} />)}
</tbody>
不要忘记key
财产。
就像您只是在调用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的工作方式。
使用数组映射功能是在React中循环遍历元素数组并根据其创建组件的一种非常常见的方法,这是一种很好的循环方法,在JSX中是一种非常高效且整洁的循环方法,这不是唯一的方法的方法,但首选的方法。
另外,不要忘记根据需要为每个迭代都拥有唯一的Key。Map函数从0开始创建一个唯一索引,但是不建议使用产生的索引,但是如果您的值是唯一的或存在唯一键,则可以使用它们:
<tbody>
{numrows.map(x=> <ObjectRow key={x.id} />)}
</tbody>
另外,如果您不熟悉Array上的地图功能,则可以从MDN发几行:
map依次为数组中的每个元素调用提供的回调函数,然后从结果中构造一个新的数组。仅对具有已分配值(包括未定义)的数组索引进行调用。不会为缺少数组的元素(即从未设置,已删除或从未分配值的索引)调用它。
使用三个参数调用callback:元素的值,元素的索引以及要遍历的Array对象。
如果提供thisArg参数来映射,它将用作回调的this值。否则,未定义的值将用作此值。该回调最终可观察到的值是根据用于确定函数所看到的值的常规规则确定的。
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>
好问题。
当我想添加一定数量的组件时,我要做的就是使用一个辅助函数。
定义一个返回JSX的函数: