如何渲染重复的 React 元素?
Posted
技术标签:
【中文标题】如何渲染重复的 React 元素?【英文标题】:How can I render repeating React elements? 【发布时间】:2014-10-28 01:59:28 【问题描述】:我已经编写了一些代码来渲染 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
循环,或者一些类似的方法。)
【问题讨论】:
你想要这样的东西吗? ***.com/questions/22876978/loop-inside-react-jsx 是的,这就是我想要的,但接受的答案与我已经在编写的丑陋代码大致相同。一定有更好的办法…… 我希望这会有所帮助***.com/a/37600679/1785635 【参考方案1】:您可以将表达式放在大括号内。请注意编译后的 javascript 为什么在 JSX 语法中不可能出现 for
循环; JSX 相当于函数调用和糖化函数参数。只允许使用表达式。
(另外:记得给循环内渲染的组件添加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);
)
)
);
)
)
)
);
【讨论】:
不错的收获。我在顶部添加了缺少的括号并从for
切换到map
。由于我不知道每个数据结构中的数据是什么,因此我假设行是数组,并将迭代的索引用于key
。当从数组中添加/删除数据时,这将导致不必要的重新渲染。您应该将key
切换为唯一标识数据且不依赖于数组的顺序和/或大小的值。
@ssorallen 感谢您的回答。在接受您的回答之前,我会将这个问题留待几天,以防有更好的方法来做这件事。我认为我的问题是 JSX 似乎没有针对for
循环和类似的非表达式转义,也没有循环的模板语法。
@chrisdew JSX 不是模板语言,它是普通 JavaScript 的语法糖。您不会像从模板语言中所期望的那样获得运算符。尝试将此答案中的代码粘贴到实时 JSX compiler 中,以了解它在做什么以及为什么永远不可能使用 for
循环。
能否为每一行添加 onClick 事件并将行项目传递给函数?我正在尝试这样的事情,但我得到了 Uncaught TypeError: Cannot read property 'clickHandler' of undefined clickHandler() console.log('on click row'); this.props.rows.map(function(row, i) return ( 由于Array(3)
将创建un-iterable array,因此必须填充它以允许使用map
数组方法。一种“转换”的方式
是在 Array-brackets 中破坏它,这“强制”Array 填充undefined
值,与Array(N).fill(undefined)
相同
<table>
[...Array(3)].map((_, index) => <tr key=index/>)
</table>
另一种方法是通过数组fill()
:
<table>
Array(3).fill(<tr/>)
</table>
⚠️ 上面例子的问题是缺少
key
prop,即a must。 (不建议将迭代器的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 个小时才能够在渲染函数的循环内循环。谢谢。你拯救了我的一天。 你不能这样做而不是使用地图吗?Array.from(length: 5, (value, index) => <tr />)
【参考方案3】:
为了扩展 Ross Allen 的答案,这里有一个使用 ES6 箭头语法的更简洁的变体。
this.props.titles.map(title =>
<th key=title>title</th>
)
它的优点是 JSX 部分是隔离的(没有 return
或 ;
),因此更容易在其周围放置循环。
【讨论】:
【参考方案4】:这是 imo 最优雅的方式(使用 ES6)。用 7 个索引实例化你的空数组并在一行中映射:
Array.apply(null, Array(7)).map((i)=>
<Somecomponent/>
)
感谢 https://php.quicoto.com/create-loop-inside-react-jsx/
【讨论】:
不错!看来你也可以Array(...Array(10)).map((v, i) => <SomeComponent />)
【参考方案5】:
本着函数式编程的精神,让我们通过抽象让我们的组件更易于使用。
// 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 的替代方案是柯里化 map 函数,但人们倾向于回避柯里化。
【讨论】:
这些函数不会让开发人员有机会指定key
属性。使用索引意味着添加/删除元素将强制重新渲染可能未更改的对象。
是的,但 95% 的时间基于索引的键就足够了。对于一些罕见的例外情况,我宁愿稍微避开一点。
同意,如果有必要,确保密钥在任何给定级别都是唯一的很容易,我喜欢它。以上是关于如何渲染重复的 React 元素?的主要内容,如果未能解决你的问题,请参考以下文章
React redux和React路由器,链接更改不会重新渲染视图[重复]