提问人:fadedbee 提问时间:9/3/2014 最后编辑:isherwoodfadedbee 更新时间:11/30/2020 访问量:148064
如何渲染重复的 React 元素?
How can I render repeating React elements?
问:
我已经编写了一些代码来在 ReactJS 中渲染重复元素,但我讨厌它有多丑陋。
render: function(){
var titles = this.props.titles.map(function(title) {
return <th>{title}</th>;
});
var rows = this.props.rows.map(function(row) {
var cells = [];
for (var i in row) {
cells.push(<td>{row[i]}</td>);
}
return <tr>{cells}</tr>;
});
return (
<table className="MyClassName">
<thead>
<tr>{titles}</tr>
</thead>
<tbody>{rows}</tbody>
</table>
);
}
有没有更好的方法来实现这一目标?
(我想在模板代码中嵌入循环,或一些类似的方法。for
答:
133赞
Ross Allen
9/3/2014
#1
您可以将表达式放在大括号内。请注意,在编译的 JavaScript 中,为什么在 JSX 语法中永远不可能有循环;JSX 相当于函数调用和加糖函数参数。只允许使用表达式。for
(另外:请记住为循环中呈现的组件添加属性。key
JSX + ES2015:
render() {
return (
<table className="MyClassName">
<thead>
<tr>
{this.props.titles.map(title =>
<th key={title}>{title}</th>
)}
</tr>
</thead>
<tbody>
{this.props.rows.map((row, i) =>
<tr key={i}>
{row.map((col, j) =>
<td key={j}>{col}</td>
)}
</tr>
)}
</tbody>
</table>
);
}
JavaScript的:
render: function() {
return (
React.DOM.table({className: "MyClassName"},
React.DOM.thead(null,
React.DOM.tr(null,
this.props.titles.map(function(title) {
return React.DOM.th({key: title}, title);
})
)
),
React.DOM.tbody(null,
this.props.rows.map(function(row, i) {
return (
React.DOM.tr({key: i},
row.map(function(col, j) {
return React.DOM.td({key: j}, col);
})
)
);
})
)
)
);
}
评论
0赞
Ross Allen
9/4/2014
不错的渔获。我在顶部添加了缺少的括号,然后从 .由于我不知道每个数据结构中的数据是什么,因此我假设这些行是数组,并使用迭代的索引进行 .在数组中添加/删除数据时,将导致不必要的重新渲染。应切换到唯一标识数据且不依赖于数组的顺序和/或大小的值。for
map
key
key
0赞
fadedbee
9/4/2014
@ssorallen 感谢您的回答。在接受你的答案之前,我会把这个问题搁置几天,以防有更好的方法。我认为我的问题是 JSX 似乎没有非表达式转义,for 循环和类似的东西,也没有循环的模板语法。for
1赞
Ross Allen
9/5/2014
@chrisdew JSX 不是一种模板语言,它是普通旧 JavaScript 的语法糖。你不会得到你所期望的模板语言的运算符。尝试将此答案中的代码粘贴到实时 JSX 编译器中,以了解它正在做什么以及为什么永远不可能循环。for
0赞
Kiran
3/10/2017
您可以为每行添加 onClick 事件并将行项传递给函数吗?我正在尝试这样的事情,但我得到未捕获的 TypeError:无法读取未定义的 clickHandler() { console.log('点击行'); } <tbody> {this.props.rows.map(function(row, i) { return ( <tr key={i} onClick=this.clickHandler()> {row.map(function(col, j) { return <td key={j}>{col}</td>; })} </tr> ); })} </tbody>
0赞
Kiran
3/10/2017
没关系,我已经将 .bind(this) 添加到 map 方法中,然后该方法将涉及每一行。谢谢。
2赞
Brigand
9/4/2014
#2
本着函数式编程的精神,让我们通过使用抽象来使我们的组件更容易使用。
// converts components into mappable functions
var mappable = function(component){
return function(x, i){
return component({key: i}, x);
}
}
// maps on 2-dimensional arrays
var map2d = function(m1, m2, xss){
return xss.map(function(xs, i, arr){
return m1(xs.map(m2), i, arr);
});
}
var td = mappable(React.DOM.td);
var tr = mappable(React.DOM.tr);
var th = mappable(React.DOM.th);
现在我们可以这样定义渲染:
render: function(){
return (
<table>
<thead>{this.props.titles.map(th)}</thead>
<tbody>{map2d(tr, td, this.props.rows)}</tbody>
</table>
);
}
JSBIN的
我们的 map2d 的替代方案是咖喱地图函数,但人们往往会回避咖喱。
评论
0赞
Ross Allen
9/4/2014
这些函数不会给开发人员指定属性的机会。使用索引意味着添加/删除元素将强制重新渲染可能未更改的对象。key
0赞
Brigand
9/4/2014
没错,但 95% 的情况下,基于索引的键就足够了。我宁愿在一些罕见的例外上走得更远一点。
0赞
Ryan Ore
5/3/2016
同意,如果有必要,确保密钥在任何给定级别上都是唯一的很容易,我喜欢它。
14赞
Jodiug
11/2/2016
#3
为了扩展 Ross Allen 的答案,这里有一个使用 ES6 箭头语法的稍微干净的变体。
{this.props.titles.map(title =>
<th key={title}>{title}</th>
)}
它的优点是 JSX 部分是隔离的(无或),因此更容易在它周围放置一个循环。return
;
3赞
Chris
10/12/2017
#4
imo,这是最优雅的方式(使用 ES6)。实例化具有 7 个索引的空数组,并在一行中映射:
Array.apply(null, Array(7)).map((i)=>
<Somecomponent/>
)
向 https://php.quicoto.com/create-loop-inside-react-jsx/ 致敬
评论
2赞
magritte
6/12/2018
好!看来你也可以做到Array(...Array(10)).map((v, i) => <SomeComponent />)
20赞
vsync
7/16/2018
#5
由于将创建一个不可迭代的数组,因此必须填充它以允许使用 Array 方法。一种“转换”的方式
是在数组括号内将其破坏,这“强制”数组填充值,与Array(3)
map
undefined
Array(N).fill(undefined)
<table>
{ [...Array(3)].map((_, index) => <tr key={index}/>) }
</table>
另一种方法是通过 Array fill():
<table>
{ Array(3).fill(<tr/>) }
</table>
⚠️ 上面例子的问题是缺少道具,这是必须的。
(不建议使用迭代器的 AS)key
index
key
嵌套节点:
const tableSize = [3,4]
const Table = (
<table>
<tbody>
{ [...Array(tableSize[0])].map((tr, trIdx) =>
<tr key={trIdx}>
{ [...Array(tableSize[1])].map((a, tdIdx, arr) =>
<td key={trIdx + tdIdx}>
{arr.length * trIdx + tdIdx + 1}
</td>
)}
</tr>
)}
</tbody>
</table>
);
ReactDOM.render(Table, document.querySelector('main'))
td{ border:1px solid silver; padding:1em; }
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<main></main>
评论
2赞
Shwe
5/18/2019
我花了至少 2 个小时才能在渲染函数中循环循环。谢谢。你救了我的一天。
2赞
creativehandle
6/5/2019
你不能这样做而不是使用地图吗?Array.from({length: 5}, (value, index) => <tr />)
评论