import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component{
constructor(props) {
super(props)
this.state = {
list: [{id: 1,val: 'aa'}, {id: 2, val: 'bb'}, {id: 3, val: 'cc'}]
}
}
click() {
this.state.list.reverse()
this.setState({})
}
render() {
return (
<ul>
<div onClick={this.click.bind(this)}>reverse</div>
{
this.state.list.map(function(item, index) {
return (
<Li key={item.id} val={item.val}></Li>
)
}.bind(this))
}
</ul>
)
}
}
class Li extends React.Component{
constructor(props) {
super(props)
}
componentDidMount() {
console.log('===did===')
}
componentWillUpdate(nextProps, nextState) {
console.log('===mount====')
}
render() {
return (
<li>
{this.props.val}
<input type="text"></input>
</li>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'))
当我设置key为item.id
时,我设置了三个输入标签a
, b
, c
;
当我点击反向时,组件 Li 将挂载,输入将反向
当我将键更改为index
时,当我点击reverse时,组件Li更新,输入标签不会改变,
我想知道这是怎么发生的?有没有人知道 key 是如何工作的?
最佳答案
正如@DuncanThacker 解释的 key
用于标识唯一元素,以便在两次渲染之间 React 知道元素是新元素还是更新元素。请记住,React 会比较每个渲染以确定 DOM 中实际更改的内容。
现在解释您所看到的行为:
when I set key as
item.id
, and I set three input tagsa, b, c
;when I click reverse, the component Li will mount, input will reverse
当您使用 id
时作为key
您可以重新排序数组,但 React 只会在第一次时创建和挂载节点。您正在输出 ===mount===
里面componentWillUpdate
,这就是为什么您会看到误导性的输出,但 React 仅更新节点(根据需要移动它们)。内部状态input
也遵循每个 <Li>
组件到它的新位置,因为 React 正确地理解了 <Li>
移动,而不是简单地用不同的内容重新绘制。
when I change key as
index
, when I click reverse, the component Li update, and the input tag will not change
当您使用 index
时作为key
React 有效地将每个渲染 channel 视为以相同顺序但内容不同的方式渲染数组,因为每个元素的 key
是一样的index
无论数组内容的顺序如何。这也是为什么内部 input
留在同一个地方,即使 val
标签呈现在不同的位置。 这正是您不应该使用 index
的原因作为key
.
你可以这样说明:
|-----------------------|---------------------|--------------------------|
| Before | After | Change |
|-----------------------|---------------------|--------------------------|
数组:
|-----------------------|---------------------|--------------------------|
| { id: 1, val: "A" } | { id: 3, val: "C" } | Moved from last to first |
| { id: 2, val: "B" } | { id: 2, val: "B" } | None |
| { id: 3, val: "C" } | { id: 1, val: "A" } | Moved from first to last |
|-----------------------|---------------------|--------------------------|
渲染 key
来自 index
:
|-----------------------|---------------------|--------------------------|
| <Li key=0 val="A"> | <Li key=0 val="C"> | Val changed "A" to "C" |
| <Li key=1 val="B"> | <Li key=1 val="B"> | None |
| <Li key=2 val="C"> | <Li key=2 val="A"> | Val changed "C" to "A" |
|-----------------------|---------------------|--------------------------|
渲染 key
来自 item.id
:
|-----------------------|---------------------|--------------------------|
| <Li key=1 val="A"> | <Li key=3 val="C"> | Moved from bottom to top |
| <Li key=2 val="B"> | <Li key=2 val="B"> | None |
| <Li key=3 val="C"> | <Li key=1 val="A"> | Moved from top to bottom |
|-----------------------|---------------------|--------------------------|
总结:您应该始终使用 id
或其他一些唯一元素标识符,如 key
.
另请参阅:https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
关于javascript - React key 如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45981597/