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'))
when I set key as item.id
, and I set three input tags a
, b
, c
;
when I click reverse, the component Li will mount, input will reverse
when I change key as index
, when I click reverse, the component Li update, and the input tag will not change,
I want to know how does it happen? Does Anyone have found out how key works?
As @DuncanThacker explained the
key
is used to identify unique elements, so that between 2 render passes React knows if an element is a new thing or an updated thing. Remember that React diffs each render to determine what actually changed in the DOM.Now to explain the behavior you're seeing:
When you use
id
askey
you can re-order the array but React will only create and mount the node the first time. You are outputting===mount===
insidecomponentWillUpdate
, which is why you see that misleading output, but React is only updating the nodes (moving them as needed). The state of the innerinput
also follows each<Li>
component to its new position, since React correctly understands that the<Li>
moved, not simply re-drawn with different content.When you use
index
askey
React effectively sees each render pass as rendering the array in the same order but with different content, since each element'skey
is the sameindex
no matter what order the array content is in. This is also why the innerinput
stays in the same place, even though theval
label is rendered in a different position. And this is exactly why you should not useindex
askey
.You could illustrate it like this:
Array:
Render
key
fromindex
:Render
key
fromitem.id
:Summary: you should always use
id
or some other unique element identifier askey
.See also: https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318