在 Reconciliation 的 ReactJS 页面中,有两个例子:
截至 2020 年 2 月 18 日,尚不清楚如何在页面上重现该问题。我尝试了几次单击“添加新的开始”或“结束”并重新排序列表,它们似乎工作正常。直到后来我才发现你需要在框中输入一些文本,然后只需“Add New to End”,然后重复三遍,然后重新排列列表。
在第一个示例中,输入框中的文本没有重新排序。在第二个示例中,输入框中的文本按预期重新排序。
这两个程序的不同之处在于使用
<ToDo key={index} {...todo} />
对比
<ToDo key={todo.id} {...todo} />
在两个版本之间还有一些稍微重新排序的代码和使用todoCounter
vs toDoCounter
(capital D
),我想知道为什么,React 团队可能会在以后修复它。但是您可以将第一个版本从key={index}
to修改key={todo.id}
,您也可以看到问题已解决。
但是当我查看代码时,输入框实际上并没有将文本数据添加到状态属性list
(数组)中。只有id
和createdAt
被添加到每个新条目list
。
因此,虽然我们可以说使用key={todo.id}
解决了问题,但首先是什么导致了问题?
您可以说id
andcreatedAt
已正确排序。没有正确排序的是输入框...但是根据和解规则决定是否刷新页面上的实际DOM元素,新的Virtual DOM子树与之前的虚拟DOM子树进行比较。
现在输入框的“属性”value
不是虚拟 DOM 的一部分,除非 React 实际上默默地把它value
放入虚拟 DOM 中。
所以当递归地“diff'ing”时,React 应该认为输入框都是一样的。这就是它的工作原理:如果我们使用key={index}
,现在 React 将当前虚拟 DOM 子树中的每一列与前一列进行比较,并看到“ID”和“createAt”单元格不同,因此强制刷新实际的 DOM。React 看到的输入框都是一样的,并没有费心去强制刷新实际的 DOM。
但是,如果我们使用key={todo.id}
,现在 React 会认为,整行是不同的,因为行“id”已经改变。因此 React 将强制刷新整行的实际 DOM,包括输入框。
所以我们可以说,只有当某些数据不在虚拟 DOM 子树中时才会出现此错误……这很少见,例如在当前情况下。在其他情况下,所有数据都将由render()
类组件或return
函数组件提供,因此能够告诉 ReactJS,“是的,强制刷新到实际的 DOM”。
这真的是这样吗?