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
keyis 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
idaskeyyou 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 innerinputalso 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
indexaskeyReact effectively sees each render pass as rendering the array in the same order but with different content, since each element'skeyis the sameindexno matter what order the array content is in. This is also why the innerinputstays in the same place, even though thevallabel is rendered in a different position. And this is exactly why you should not useindexaskey.You could illustrate it like this:
Array:
Render
keyfromindex:Render
keyfromitem.id:Summary: you should always use
idor some other unique element identifier askey.See also: https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318