How can I render repeating React elements?
我写了一些代码来渲染ReactJS中的重复元素,但我讨厌它是多么丑陋。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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循环,或者类似的方法。)
-
你想要这样的东西吗?stackoverflow.com/questions/22876978/loop-inside-react-jsx
-
是的,这就是我想要的,但是接受的答案与我已经写过的丑陋代码大致相同。 肯定有更好的办法...
-
我希望这将有助于stackoverflow.com/a/37600679/1785635
您可以将表达式放在大括号内。请注意,在编译的JavaScript中,为什么在JSX语法中永远不可能有for循环; JSX相当于函数调用和含糖函数参数。只允许表达式。
(另外:请记住将key属性添加到循环内呈现的组件中。)
JSX + ES2015:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 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的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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);
})
)
);
})
)
)
);
} |
-
好捕获。我在顶部添加了缺少的括号,并从for切换到map。由于我不知道每个数据结构中的数据是什么,我假设行是数组并使用key的迭代索引。从数组中添加/删除数据时,将导致不必要的重新呈现。您应该将key切换为唯一标识数据的值,并且该值不依赖于数组的顺序和/或大小。
-
@ssorallen感谢您的回答。在接受你的回答之前,我会将这个问题保持开放几天,以防有更好的方法。我认为我的问题是JSX似乎没有非表达式转义,对于for循环和类似的,它也没有循环的模板语法。
-
@chrisdew JSX不是一种模板语言,它是普通旧JavaScript的语法糖。您不会像模板语言那样获得运算符。尝试将此答案中的代码粘贴到实时JSX编译器中,以了解它正在做什么以及为什么for循环永远不可能。
-
你能为每一行添加onClick事件并将行项传递给函数吗?我正在尝试这样的事情,但我得到Uncaught TypeError:无法读取未定义的clickHandler(){console.log('on click row')的属性'clickHandler'; }
{this.props.rows.map(function(row,i){return(
{row.map(function(col,j){return
{col} td>;})} tr>);}}} tbody>
-
没关系我已经将.bind(this)添加到map方法中,然后该方法将涉及每一行。谢谢。
为了扩展Ross Allen的答案,这里有一个使用ES6箭头语法的略微更清晰的变体。
1 2 3
| {this.props.titles.map(title =>
<th key={title}>{title}</th>
)} |
它的优点是JSX部分是隔离的(没有return或;),因此更容易围绕它进行循环。
浅(通过数组from():
1 2 3
| <table>
{ Array.from({length:3}, (value, index) => <tr key={value.id} />) }
</table> |
另一种方法是通过Array fill():
1 2 3
| <table>
{ Array(3).fill(<tr />) }
</table> |
嵌套节点:
1 2 3 4 5 6 7 8 9 10 11 12 13
| var table = (
<table>
{ Array.from(Array(3)).map((tr, tr_i) =>
<tr>
{ Array.from(Array(4)).map((a, td_i, arr) =>
<td>{arr.length * tr_i + td_i + 1}</td>
)}
</tr>
)}
</table>
);
ReactDOM.render(table, document.querySelector('main')) |
1
| td{ border:1px solid silver; padding:1em; } |
1 2 3
| <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js">
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js">
<main></main> |
-
我花了至少2个小时才能在循环中循环渲染功能。谢谢。你救了我的一天。
-
你不能这样做而不是使用地图吗? Array.from({length: 5}, (value, index) =>
)
-
@creativehandle - 是的,谢谢!,更新了答案
本着函数式编程的精神,让我们通过使用抽象使我们的组件更容易使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| // 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); |
现在我们可以像这样定义渲染:
1 2 3 4 5 6 7 8
| render: function(){
return (
<table>
<thead>{this.props.titles.map(th)}</thead>
<tbody>{map2d(tr, td, this.props.rows)}</tbody>
</table>
);
} |
jsbin
我们map2d的替代方案是一个咖喱的地图功能,但人们往往会回避干扰。
-
这些函数不会让dev有机会指定key属性。使用索引意味着添加/删除元素将强制重新呈现可能未更改的对象。
-
是的,但基于索引的密钥有95%的时间是足够的。我宁愿在有些罕见的例外情况下稍微偏离一点。
-
同意,如果有必要,确保密钥在任何给定级别都是唯一的,我很喜欢它。
这是imo最优雅的方式(使用ES6)。使用7个索引实例化空数组并将其映射到一行:
1 2 3
| Array.apply(null, Array(7)).map((i)=>
<Somecomponent/>
) |
荣誉
Create loop inside React JSX
-
太好了!似乎你也可以做Array(...Array(10)).map((v, i) => )
|