【发布时间】:2016-08-12 11:08:42
【问题描述】:
我正在制作 React Elements 的集合并展示它们;下面是一个简单的例子,用来描述一个如何修改一个预先存在的实例化元素的问题。
var c = [
<div>A</div>,
<div>B</div>,
// ...
<div>Z</div>
];
var ListComponents = React.createClass({
render: function() {
return <div>{c}</div>;
}
});
ReactDOM.render(<ListComponents/>, document.getElementById('root'));
虽然上面的代码“有效”,但它会呈现一条我不想忽略的控制台消息:
警告:数组或迭代器中的每个孩子都应该有一个唯一的“key”道具。 检查 `ListComponents` 的渲染方法。 有关详细信息,请参阅 https://fb.me/react-warning-keys。
从表面上看,我可以为c 中的每个元素添加一个唯一的key="…" 字符串并完成它。
但是,这似乎很冗长,特别是因为我有一个索引数组中的数据和一种函数式语言,理论上可以为每个键分配其匹配的索引值,而无需手动输入它作为源文字。
我很想能够做到这一点......
c.forEach( (e,i) => e.key = i ); // ...or call some setter
什么是*正确的* React 方法来做到这一点 - 并且 - 保持代码干净?
附录: ...对于好奇或只想说添加关键字段的人...
我使用的集合实际上是一个元组数组,包含元数据和相应的 React 元素、自定义组件或一些巨大的 JSX 块。上面的示例过于简单化了实际数据的外观及其不规则性。
由于源数据本身很长,经常更新,并且不是由开发人员维护的;它很容易出现遗漏关键字段或重复手动输入的值。因此,希望完全以编程方式完成。我不能指望数据所有者正确地做到这一点。他们无法阅读代码,所以理想情况下,我宁愿不要用大量“编程垃圾”来搞乱数据结构。
对集合进行了几次操作,将某些元素的各种运行放入其他动态创建的包装器中,以便最终的集合在最终显示之前实际上是由一些转换、过滤器和映射生成的。
【问题讨论】:
-
可能你不能,因为 React 冻结了元素本身及其属性:
Object.freeze(element.props); Object.freeze(element);github.com/facebook/react/blob/… -
为什么不将数据转换和 JSX 生成步骤分开呢?先准备只包含纯数据的数组
c,然后在组件中用c.map((v, i) => <div key={i}>{v}</div>)渲染。 -
这不是“表面上”,而是“遵循 React 的系统进行有效差异化”。 React 不知道你刚刚声明了一个一次性数组,它所看到的只是你传入一个它需要 的元素列表,以便在每次
render()调用时有效地进行差异。它需要这些键来识别发生了哪些元素修改,即使你告诉自己你永远不会改变它们。 -
@zerkms -- 问题在于输入数据的人认为他们正在输入 HTML 并且不懂编程,否则这正是我处理解决方案。唉,真正的数据是异构的,不仅仅是像过于琐碎的例子中所示的 DIV,而是各种元素,包括为它们制作的一些自定义标签。不过,谢谢。
-
然而,这种方法的问题在于索引不是唯一标识。如果它在您使用
map()和sort().map()时识别出 不同的 元素,那么您的密钥是假密钥,并且您会对 React 有效地进行虚拟 DOM diffing 的能力产生不利影响。如果您对此感到满意,那么就没有问题,但是如果您想做“正确”的事情,则不能使用数组位置来唯一标识项目,因为它们不能。他们以任何方式对条目只字不提,只对条目所在的列表说了些什么。或者只是忽略警告,这也有效。
标签: javascript reactjs functional-programming react-jsx jsx