我正在尝试在 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 的新手,我不确定如何实现上述目标(多次添加组件)。
把它想象成你只是在调用 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 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 的工作原理。
我不确定这是否适合您的情况,但通常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>
如果您还没有一个数组来map()
喜欢@FakeRainBrigand 的答案,并且想要内联它,那么源布局对应的输出比@SophieAlpert 的答案更接近:
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。
Array.apply
<tbody>
{Array.apply(0, Array(10)).map(function (x, i) {
return <ObjectRow key={i} />;
})}
</tbody>
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>
);
}
Array
方法Array.prototype.fill
您可以这样做作为使用 spread 的替代方法,如上图所示:
<tbody>
{Array(10).fill(1).map((el, i) =>
<ObjectRow key={i} />
)}
</tbody>
(我认为你实际上可以省略任何参数fill()
,但我不是 100% 的。)感谢@FakeRainBrigand 纠正了我在早期版本的fill()
解决方案中的错误(见修订)。
key
在所有情况下,key
attr 都会减轻开发构建的警告,但在子级中无法访问。如果您希望子级中的索引可用,则可以传递额外的 attr。请参阅列表和键进行讨论。
简单地使用ES6 语法的map Array方法:
<tbody>
{items.map(item => <ObjectRow key={item.id} name={item.name} />)}
</tbody>
不要忘记key
财产。
在React中,使用Array map函数是循环遍历元素数组并根据它们创建组件的一种非常常见的方法。这是执行循环的好方法,它非常有效,并且是在JSX中执行循环的整洁方法。这不是唯一的方法,而是首选的方法。
此外,不要忘记根据需要为每次迭代都有一个唯一的密钥。map 函数从 0 开始创建唯一索引,但不建议使用生成的索引,但如果您的值是唯一的或存在唯一键,则可以使用它们:
<tbody>
{numrows.map(x=> <ObjectRow key={x.id} />)}
</tbody>
另外,如果您不熟悉 Array 上的 map 函数,请参考MDN的几行代码:
map 按顺序为数组中的每个元素调用一次提供的回调函数,并根据结果构造一个新数组。回调仅针对具有赋值的数组索引调用,包括未定义的。对于数组的缺失元素(即从未设置、已删除或从未分配值的索引),不会调用它。
callback 使用三个参数调用:元素的值、元素的索引和被遍历的 Array 对象。
如果向地图提供了 thisArg 参数,它将用作回调的 this 值。否则,值 undefined 将用作其 this 值。回调最终可观察到的这个值是根据用于确定函数看到的 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}>repeated 3 times</li>
))}
</ol>
</div>
);
}
}
有多种方法可以做到这一点。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>
);
}
您还可以在返回块之外提取:
render: function() {
var rows = [];
for (var i = 0; i < numrows; i++) {
rows.push(<ObjectRow key={i}/>);
}
return (<tbody>{rows}</tbody>);
}
您可能想查看React Templates,它允许您在 React 中使用 JSX 样式的模板,并带有一些指令(例如 rt-repeat)。
您的示例,如果您使用 react-templates,将是:
<tbody>
<ObjectRow rt-repeat="obj in objects"/>
</tbody>
如果你选择在render方法的return()中转换它,最简单的选择是使用map()方法。使用 map() 函数将数组映射为 JSX 语法,如下所示(使用 ES6 语法)。
在父组件内部:
<tbody>
{ objectArray.map(object => <ObjectRow key={object.id} object={object.value} />) }
</tbody>
请注意,该key
属性已添加到您的子组件中。如果您没有提供关键属性,您可以在控制台上看到以下警告。
警告:数组或迭代器中的每个孩子都应该有一个唯一的“key”道具。
注意:人们常犯的一个错误是index
在迭代时使用作为键。将index
元素用作键是一种反模式,您可以在此处了解更多信息。简而言之,如果它不是静态列表,则永远不要index
用作键。
现在在ObjectRow组件中,您可以从其属性访问该对象。
在 ObjectRow 组件内部
const { object } = this.props
或者
const object = this.props.object
这应该将您从父组件传递到ObjectRowobject
组件中的变量的对象获取。现在您可以根据您的目的吐出该对象中的值。
参考:
如果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 代码。此处列出了功能夹具。
<tbody>
{
Array.from(Array(i)).map(() => <ObjectRow />)
}
</tbody>
在哪里i = number of times
如果你想为渲染的组件分配唯一的键 ID,你可以按照React 文档React.Children.toArray
中的建议使用
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>
ECMAScript 2015 / 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()
你可以使用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>
)
}
这可以通过多种方式完成。
如上所述,在return
将所有元素存储在数组中之前
内循环return
方法1 let container = []; let arr = [1, 2, 3] //可以是任何数组,对象
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>
)
我用这个:
gridItems = this.state.applications.map(app =>
<ApplicationItem key={app.Id} app={app } />
);
PS:永远不要忘记钥匙,否则你会收到很多警告!
只需使用.map()
循环遍历您的集合并<ObjectRow>
从每次迭代中返回带有道具的项目。
假设objects
是某个地方的数组...
<tbody>
{ objects.map((obj, index) => <ObjectRow obj={ obj } key={ index }/> ) }
</tbody>
我倾向于采用一种方法,其中编程逻辑发生在render
. 这有助于保持实际呈现的内容易于理解。
所以我可能会做类似的事情:
import _ from 'lodash';
...
const TableBody = ({ objects }) => {
const objectRows = objects.map(obj => <ObjectRow object={obj} />);
return <tbody>{objectRows}</tbody>;
}
诚然,这是如此少量的代码,内联它可能工作得很好。
您当然可以按照其他答案的建议使用 .map 解决。如果你已经在使用Babel,你可以考虑使用jsx-control-statements。
它们需要一些设置,但我认为它在可读性方面是值得的(尤其是对于非 React 开发人员)。如果你使用 linter,还有eslint-plugin-jsx-control-statements。
这是一个简单的解决方案。
var Object_rows = [];
for (var i = 0; i < numrows; i++) {
Object_rows.push(<ObjectRow />);
}
<tbody>{Object_rows}</tbody>;
不需要映射和复杂的代码。您只需要将行推送到数组并返回值以呈现它。
您的 JSX 代码将编译为纯 JavaScript 代码,任何标签都将被ReactElement
对象替换。在 JavaScript 中,你不能多次调用一个函数来收集它们返回的变量。
这是非法的,唯一的办法就是使用数组来存储函数返回的变量。
或者您可以使用JavaScript ES5 以来Array.prototype.map
可用的方法来处理这种情况。
也许我们可以编写其他编译器来重新创建新的 JSX 语法来实现重复功能,就像Angular 的ng-repeat
.
以下是 React 文档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来区分数组中的数据。
由于您在 JSX 代码中编写 JavaScript 语法,因此您需要将 JavaScript 代码包装在花括号中。
row = () => {
var rows = [];
for (let i = 0; i<numrows; i++) {
rows.push(<ObjectRow/>);
}
return rows;
}
<tbody>
{this.row()}
</tbody>
你可以在 React for循环中使用 .map() 。
<tbody>
{ newArray.map(() => <ObjectRow />) }
</tbody>
我像这样使用它
<tbody>
{ numrows ? (
numrows.map(obj => { return <ObjectRow /> })
) : null
}
</tbody>
您还可以使用自调用函数:
return <tbody>
{(() => {
let row = []
for (var i = 0; i < numrows; i++) {
row.push(<ObjectRow key={i} />)
}
return row
})()}
</tbody>
当我想添加一定数量的组件时,我使用辅助函数。
定义一个返回 JSX 的函数:
const myExample = () => {
let myArray = []
for(let i = 0; i<5;i++) {
myArray.push(<MyComponent/>)
}
return myArray
}
//... in JSX
<tbody>
{myExample()}
</tbody>
甚至这段代码也做同样的工作。
<tbody>
{array.map(i =>
<ObjectRow key={i.id} name={i.name} />
)}
</tbody>
随着时间的推移,语言变得越来越成熟,我们经常会偶然发现这样的常见问题。问题是循环一个组件'n'次。
{[...new Array(n)].map((item, index) => <MyComponent key={index} />)}
其中,n - 是您想要循环的次数。item
将是未定义的,并且index
会像往常一样。此外,ESLint不鼓励使用数组索引作为键。
但是您的优点是不需要在之前初始化数组,最重要的是避免for
循环......
为避免 item as undefined 带来的不便,您可以使用 an _
,以便在 linting 时将其忽略并且不会引发任何 linting 错误,例如
{[...new Array(n)].map((_, index) => <MyComponent key={index} />)}
您可以执行以下操作:
let foo = [1,undefined,3]
{ foo.map(e => !!e ? <Object /> : null )}
JSX 内部的循环非常简单。试试这个:
return this.state.data.map((item, index) => (
<ComponentName key={index} data={item} />
));
Array.from是最好的方法。如果你想创建一个具有一定长度的 JSX 数组。
function App() {
return (
<tbody>
{Array.from({ length: 10 }, (_, key) => (
<ObjectRow {...{ key }} />
))}
</tbody>
);
}
上面的例子是当你没有数组的时候,所以如果你有一个数组,你应该像这样在 JSX 中映射它:
function App() {
return (
<tbody>
{list.map((item, key) => (
<ObjectRow {...{ key }} />
))}
</tbody>
);
}
如果您需要在 JSX 中使用 JavaScript 代码,请{ }
在这些括号内添加并编写 JavaScript 代码。就是这么简单。
同样的方式你可以在 JSX/react 中循环。
说:
<tbody>
{`your piece of code in JavaScript` }
</tbody>
例子:
<tbody>
{ items.map((item, index) => {
console.log(item)}) ; // Print item
return <span>{index}</span>;
} // Looping using map()
</tbody>
以下是您可以在 React 中根据迭代对象数组或普通数组执行的可能解决方案
const rows = [];
const numrows = [{"id" : 01, "name" : "abc"}];
numrows.map((data, i) => {
rows.push(<ObjectRow key={data.id} name={data.name}/>);
});
<tbody>
{ rows }
</tbody>
或者
const rows = [];
const numrows = [1,2,3,4,5];
for(let i=1, i <= numrows.length; i++){
rows.push(<ObjectRow key={numrows[i]} />);
};
<tbody>
{ rows }
</tbody>
最近几天我熟悉的用于迭代对象数组的更好方法是.map
直接在渲染中返回或不返回:
const numrows = [{"id" : 01, "name" : "abc"}];
<tbody>
{numrows.map(data=> {
return <ObjectRow key={data.id} name={data.name}/>
})}
</tbody>
const numrows = [{"id" : 01, "name" : "abc"}];
<tbody>
{numrows.map(data=> (
<ObjectRow key={data.id} name={data.name}/>
))}
</tbody>
如果你真的想要一个等效的for循环(你有一个数字,而不是一个数组),只需使用range
from Lodash。
不要重新发明轮子,也不要混淆你的代码。只需使用标准实用程序库。
import range from 'lodash/range'
range(4);
// => [0, 1, 2, 3]
range(1, 5);
// => [1, 2, 3, 4]
好吧,给你。
{
[1, 2, 3, 4, 5, 6].map((value, index) => {
return <div key={index}>{value}</div>
})
}
您所要做的就是映射您的数组并返回您想要渲染的任何内容。并且请不要忘记key
在返回的元素中使用。
如果您没有键值 par,则要打印数组值,请使用以下代码 -
<div>
{my_arr.map(item => <div>{item} </div> )}
</div>
您可以尝试新的 for of循环:
const apple = {
color: 'red',
size: 'medium',
weight: 12,
sugar: 10
}
for (const prop of apple.entries()){
console.log(prop);
}
这里有几个例子:
除非您声明一个函数并用参数将其括起来,否则这是不可能的。在 JSXExpression 中,您只能编写表达式,而不能编写诸如 for()、声明变量或类或 if() 语句之类的语句。
这就是为什么 CallExpressions 函数今天如此受欢迎的原因。我的建议:习惯他们。这就是我要做的:
const names = ['foo', 'bar', 'seba']
const people = <ul>{names.map(name => <li>{name}</li>)}</ul>
过滤:
const names = ['foo', undefined, 'seba']
const people = <ul>{names.filter(person => !!person).map(name => <li>{name}</li>)}</ul>
如果():
var names = getNames()
const people = {names && names.length &&
<ul>{names.map(name => <li>{name}</li>)}</ul> }
如果别的:
var names = getNames()
const people = {names && names.length ?
<ul>{names.map(name => <li>{name}</li>)}</ul> : <p>no results</p> }
如果你真的想在 JSX 中使用for循环,你可以使用IIFE 。
<tbody>
{
(function () {
const view = [];
for (let i = 0; i < numrows; i++) {
view.push(<ObjectRow key={i}/>);
}
return view;
}())
}
</tbody>
@jacefarm 如果我理解正确,您可以使用以下代码:
<tbody>
{ new Array(numrows).fill(<ObjectRow/>) }
</tbody>
您可以使用以下代码:
<tbody>
{ new Array(numrows).fill('').map((item, ind) => <ObjectRow key={ind}/>) }
</tbody>
还有这个:
<tbody>
new Array(numrows).fill(ObjectRow).map((Item, ind) => <Item key={ind}/>)
</tbody>
问题是您没有返回任何 JSX 元素。这种情况还有另一种解决方案,但我将提供最简单的一种:“使用地图功能”!
<tbody>
{ numrows.map(item => <ObjectRow key={item.uniqueField} />) }
</tbody>
它是如此简单和美丽,不是吗?
使用地图功能。
<tbody>
{objects.map((object, i) => <ObjectRow obj={object} key={i} />)}
</tbody>
我不确定这是否适合您的情况,但通常 [map][1] 是一个很好的答案。
如果这是您的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>
objects.map
是进行循环objects.filter
的最佳方式,也是过滤所需数据的最佳方式。过滤后的数据将形成一个新的数组,objects.some
是检查数组是否满足给定条件的最佳方法(它返回布尔值)。
你可以直接在 JSX 中做同样的事情,使用 map 而不是 for-of 循环:
render: function() {
const items = ['one', 'two', 'three'];
return (
<ul>
{items.map((value, index) => {
return <li key={index}>{value}</li>
})}
</ul>
)
}
只需执行以下操作:
<tbody>
{new Array(numRows).fill("", 0, numRows).map((p, i) => <YourRaw key={i} />)}
</tbody>
您可以执行以下操作来重复组件numrows
时间
<tbody>{Array(numrows).fill(<ObjectRow />)}</tbody>
React 元素是简单的 JavaScript,所以你可以遵循 JavaScript 的规则。您可以像这样在 JavaScript 中使用for
循环:-
<tbody>
for (var i=0; i < numrows; i++) {
<ObjectRow/>
}
</tbody>
但有效且最好的方法是使用该.map
功能。如下图:-
<tbody>
{listObject.map(function(listObject, i){
return <ObjectRow key={i} />;
})}
</tbody>
在这里,需要做一件事:定义密钥。否则它会抛出这样的警告:-
Warning.js:36 警告:数组或迭代器中的每个孩子都应该有一个唯一的“key”道具。检查
ComponentName
. 有关详细信息,请参阅“链接”。
return (
<table>
<tbody>
{
numrows.map((item, index) => {
<ObjectRow data={item} key={index}>
})
}
</tbody>
</table>
);
如果 numrows 是一个数组,就像其他答案一样,最好的方法是map
方法。如果不是并且你只能从 JSX 访问它,你也可以使用这个ES6方法:
<tbody>
{
[...Array(numrows).fill(0)].map((value,index)=><ObjectRow key={index} />)
}
</tbody>
您需要将元素添加到数组并渲染元素数组。
这有助于减少重新渲染组件所需的时间。
这里有一些粗略的代码可能会有所帮助:
MyClass extends Component {
constructor() {
super(props)
this.state = { elements: [] }
}
render() {
return (<tbody>{this.state.elements}<tbody>)
}
add() {
/*
* The line below is a cheap way of adding to an array in the state.
* 1) Add <tr> to this.state.elements
* 2) Trigger a lifecycle update.
*/
this.setState({
elements: this.state.elements.concat([<tr key={elements.length}><td>Element</td></tr>])
})
}
}
在 React 中使用map是迭代数组的最佳实践。
为了防止ES6出现一些错误,语法映射在 React 中使用如下:
<tbody>
{items.map((item, index) => <ObjectRow key={index} name={item.name} />)}
</tbody>
这里你调用了一个组件,<ObjectRow/>,所以你不需要在箭头后面加上括号。
但你也可以这样做:
{items.map((item, index) => (
<ObjectRow key={index} name={item.name} />
))}
或者:
{items.map((item, index) => {
// Here you can log 'item'
return (
<ObjectRow key={index} name={item.name} />
)
})}
我这么说是因为如果你在箭头后面加上一个括号“{}”,React 不会抛出错误并且会显示一个白名单。
您可以创建一个新组件,如下所示:
像这样将密钥和数据传递给您的ObjectRow
组件:
export const ObjectRow = ({key,data}) => {
return (
<div>
...
</div>
);
}
创建一个新组件ObjectRowList
以充当数据容器:
export const ObjectRowList = (objectRows) => {
return (
<tbody>
{objectRows.map((row, index) => (
<ObjectRow key={index} data={row} />
))}
</tbody>
);
}
render() {
const elements = ['one', 'two', 'three'];
const items = []
for (const [index, value] of elements.entries()) {
items.push(<li key={index}>{value}</li>)
}
return (
<div>
{items}
</div>
)
}
你必须用 JSX 编写:
<tbody>
{
objects.map((object, i) => (
<ObjectRow obj={object} key={i} />
));
}
</tbody>
我找到了另一种遵循地图渲染的解决方案:
<tbody>{this.getcontent()}</tbody>
还有一个单独的功能:
getcontent() {
const bodyarea = this.state.movies.map(movies => (
<tr key={movies._id}>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.publishDate}</td>
<td>
<button
onClick={this.deletMovie.bind(this, movies._id)}
className="btn btn-danger"
>
Delete
</button>
</td>
</tr>
));
return bodyarea;
}
这个例子很容易解决很多问题。
在 JSX 块中使用{}
JavaScript 代码,以使其正确执行您尝试执行的任何 JavaScript 操作。
<tr>
<td>
{data.map((item, index) => {
{item}
})}
</td>
</tr>
这有点模糊,但您可以为任何数组交换数据。这将为您提供每个项目的表格行和表格项目。如果您在数组的每个节点中不止一个东西,您将希望通过执行以下操作来专门针对它:
<td>{item.someProperty}</td>
在这种情况下,您将希望用不同的包围它并以不同的方式td
排列前面的示例。
在迭代数组和生成 JSX 元素方面发布了许多解决方案。它们都很好,但是它们都直接在循环中使用了索引。我们推荐使用 data 中的唯一 id 作为 key,但是当我们没有数组中每个对象的唯一 id 时,我们会使用 index 作为 key,但不建议直接使用 index 作为 key。
还有一件事为什么我们选择.map,但为什么不选择 .foEach 因为 .map 返回一个新数组。这些天有不同的方式来做.map 。
下面使用 .map 的不同版本详细说明了如何使用唯一键以及如何使用 .map 循环 JSX 元素。
.map从数据中返回单个 JSX 元素和唯一 id 作为键版本时不返回:
const {objects} = this.state;
<tbody>
{objects.map(object => <ObjectRow obj={object} key={object.id} />)}
</tbody>
从数据中返回多个 JSX 元素和唯一 id 作为键版本时不返回的.map
const {objects} = this.state;
<tbody>
{objects.map(object => (
<div key={object.id}>
<ObjectRow obj={object} />
</div>
))}
</tbody>
.map在返回单个 JSX 元素和索引作为键版本时不返回:
const {objects} = this.state;
<tbody>
{objects.map((object, index) => <ObjectRow obj={object} key={`Key${index}`} />)}
</tbody>
.map在返回多个 JSX 元素和索引作为键版本时不返回:
const {objects} = this.state;
<tbody>
{objects.map((object, index) => (
<div key={`Key${index}`}>
<ObjectRow obj={object} />
</div>
))}
</tbody>
返回多个 JSX 元素和索引作为键版本时返回的.map :
const {objects} = this.state;
<tbody>
{objects.map((object, index) => {
return (
<div key={`Key${index}`}>
<ObjectRow obj={object} />
</div>
)
})}
</tbody>
.map当返回多个 JSX 元素和数据中的唯一 id 作为键版本时返回:
const {objects} = this.state;
<tbody>
{objects.map(object => {
return (
<div key={object.id}>
<ObjectRow obj={object} />
</div>
)
})}
</tbody>
另一种方式是
render() {
const {objects} = this.state;
const objectItems = objects.map(object => {
return (
<div key={object.id}>
<ObjectRow obj={object} />
</div>
)
})
return(
<div>
<tbody>
{objectItems}
</tbody>
</div>
)
}
如果您想使用存储为Integer
-value 的特定行数,可以提供更直接的解决方案。
在我们的帮助下,typedArrays
我们可以通过以下方式实现所需的解决方案。
// Let's create a typedArray with length of `numrows`-value
const typedArray = new Int8Array(numrows); // typedArray.length is now 2
const rows = []; // Prepare rows-array
for (let arrKey in typedArray) { // Iterate keys of typedArray
rows.push(<ObjectRow key={arrKey} />); // Push to an rows-array
}
// Return rows
return <tbody>{rows}</tbody>;
<tbody>
numrows.map((row,index) => (
return <ObjectRow key={index}/>
)
</tbody>
也许是当今最大开发人员的标准,使用这样的结构:
let data = [
{
id: 1,
name: "name1"
},
{
id: 2,
name: "name2"
},
{
id: 3,
name: "name3"
},
{
id: 100,
name: "another name"
}
];
export const Row = data => {
return (
<tr key={data.id}>
<td>{data.id}</td>
<td>{data.name}</td>
</tr>
);
};
function App() {
return (
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>{data.map(item => Row(item))}</tbody>
</table>
);
}
在 JSX 中,在 HTML 或此处的任何代码中编写 JavaScript 操作{data.map(item => Row(item))}
,使用单个花括号并在 map 函数中。了解更多关于地图的信息。
还可以在此处查看以下输出。
在 JSX 中循环有多种方式
使用for循环
function TableBodyForLoop(props) {
const rows = []; // Create an array to store list of tr
for (let i = 0; i < props.people.length; i++) {
const person = props.people[i];
// Push the tr to array, the key is important
rows.push(
<tr key={person.id}>
<td>{person.id}</td>
<td>{person.name}</td>
</tr>
);
}
// Return the rows inside the tbody
return <tbody>{rows}</tbody>;
}
使用ES6数组映射方法
function TableBody(props) {
return (
<tbody>
{props.people.map(person => (
<tr key={person.id}>
<td>{person.id}</td>
<td>{person.name}</td>
</tr>
))}
</tbody>
);
}
完整示例:https ://codesandbox.io/s/cocky-meitner-yztif
以下 React 文档会有所帮助
人们如何使用更新的语法或不常见的方法来创建数组来给出“创造性”的答案,这很有趣。在我使用 JSX 的经验中,我看到这些技巧只被没有经验的 React 程序员使用。
解决方案越简单——对未来的维护者来说就越好。而且由于 React 是一个 Web 框架,通常这种类型的(表)数据来自 API。因此,最简单和最实用的方法是:
const tableRows = [
{id: 1, title: 'row1'},
{id: 2, title: 'row2'},
{id: 3, title: 'row3'}
]; // Data from the API (domain-driven names would be better of course)
...
return (
tableRows.map(row => <ObjectRow key={row.id} {...row} />)
);
您只能在 JSX 元素中编写 JavaScript 表达式,因此for循环无法工作。您可以先将元素转换为数组,然后使用map
函数进行渲染:
<tbody>
{[...new Array(numrows)].map((e) => (
<ObjectRow/>
))}
</tbody>
在地图中包含 JSX 内容可能是笨拙的语法。相反,您可以这样做:
const ObjectRow = ({ ... }) => <tr key={}>...</tr>
const TableBody = ({ objects }) => {
return <tbody>{objects.map(ObjectRow)}</tbody>;
}
这是简写
{ objects.map(object => ObjectRow(object))
如果 ObjectRow 设置为采用与 中相同的键object
,这将非常有效。
注意 - 您可能需要在key
渲染 ObjectRow 时设置道具。不能通过函数调用传入。
更多注意事项- 我遇到了一些这种技术是个坏主意的地方。例如,它不会通过正常的创建组件路径,也不会默认 prop 值,所以要小心。尽管如此,了解它还是很方便的,有时也很有用。
我见过一个人/以前的答案在数组中使用 .concat() ,但不是这样......
我使用concat添加到字符串,然后通过 jQuery 选择器在元素上呈现 JSX 内容:
let list = "<div><ul>";
for (let i=0; i<myArray.length; i++) {
list = list.concat(`<li>${myArray[i].valueYouWant}</li>`);
}
list = list.concat("</ul></div>);
$("#myItem").html(list);
const numrows = [1, 2, 3, 4, 5];
cosnt renderRows = () => {
return numros.map((itm,index) => <td key={index}>{itm}</td>)
}
return <table>
............
<tr>
{renderRows()}
</tr>
</table>
在你的渲染或任何函数中,在返回之前,你可以使用一个变量来存储 JSX 元素。像这样 -
const tbodyContent = [];
for (let i=0; i < numrows; i++) {
tbodyContent.push(<ObjectRow/>);
}
像这样在你的身体内使用它:
<tbody>
{
tbodyContent
}
</tbody>
但我更喜欢map()。
function PriceList({ self }) {
let p = 10000;
let rows = [];
for(let i=0; i<p; i=i+50) {
let r = i + 50;
rows.push(<Dropdown.Item key={i} onClick={() => self.setState({ searchPrice: `${i}-${r}` })}>{i}-{r} ₺</Dropdown.Item>);
}
return rows;
}
<PriceList self={this} />
如果你习惯了 Angular 并且想要一个更像 React 的方法:
尝试使用类似于 Angular 的带有自动散列和可选 trackBy 的简单组件。
<For items={items}>
{item => <div>item</div>}
</For>
<For items={items} trackBy={'name'}>
{item => <div>item</div>}
</For>
export default class For<T> extends Component<{ items: T[], trackBy?: keyof T, children: (item: T) => React.ReactElement }, {}> {
render() {
return (
<Fragment>
{this.props.items.map((item: any, index) => <Fragment key={this.props.trackBy ?? item.id ?? index}>{this.props.children(item)}</Fragment>)}
</Fragment>
);
}
}
试试这个
<tbody>
{new Array(numrows).map((row,index)=><ObjectRow key={***someThingUniqe***}/>)} //don't use index as key
</tbody>
如果你想知道为什么你不应该在反应中使用索引作为键检查 这个
您可以将 numrows 置于状态并使用map()而不是for循环:
{this.state.numrows.map((numrows , index) => {
return (
<ObjectRow
key={index}
/>
使用地图循环
Array.map(arrayItem => {
return <ObjectRow arrayItem={arrayItem}/> // pass array item in component
})