【问题标题】:How does React key works?React 键是如何工作的?
【发布时间】:2018-02-09 10:02:33
【问题描述】:

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时,我设置了三个输入标签abc

当我点击反向时,组件 Li 会挂载,输入会反向

当我把key改成index时,当我点击reverse时,组件li更新,输入标签不会改变,

我想知道它是怎么发生的?有人知道 key 是如何工作的吗?

【问题讨论】:

标签: javascript html reactjs virtual-dom


【解决方案1】:

正如@DuncanThacker 解释的那样,key 用于识别唯一元素,因此在 2 次渲染传递之间,React 知道一个元素是新事物还是更新事物。请记住,React 对每个渲染进行比较以确定 DOM 中实际发生的变化。

现在解释一下你看到的行为:

当我设置key为item.id时,我设置了三个输入标签a, b, c;

当我点击反向时,组件 Li 会挂载,输入会反向

当您将id 用作key 时,您可以重新排序数组,但React 只会在第一次时间创建和挂载节点。你在componentWillUpdate 中输出===mount===,这就是为什么你会看到误导性的输出,但React 只是更新节点(根据需要移动它们)。内部input 的状态也跟随每个&lt;Li&gt; 组件到它的新位置,因为React 正确理解&lt;Li&gt; 移动,而不是简单地用不同的内容重新绘制。

当我将 key 更改为index 时,当我点击反向时,组件 Li 更新,输入标签不会改变

当您将index 用作key 时,React 有效地将每个渲染过程视为以相同的顺序渲染数组,但内容不同,因为每个元素的key 是相同的@987654336 @不管数组内容的顺序是什么。这也是为什么内部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 |
|-----------------------|---------------------|--------------------------|

index渲染key

|-----------------------|---------------------|--------------------------|
| <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"   |
|-----------------------|---------------------|--------------------------|

item.id渲染key

|-----------------------|---------------------|--------------------------|
| <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

【讨论】:

    【解决方案2】:

    React 使用“key”属性来确定是渲染一个全新的组件实例,还是更新现有的实例。因此,使用 item id 作为 key 意味着该 item 的组件不会被销毁和重新创建。如果您向列表中添加一个新项目,它将创建一个新组件,如果您删除一个项目,它将破坏旧项目,但如果您更新一个项目而不更改其 ID,则该组件只会更新。

    它对动态列表很有用,因为它减少了安装的组件从呈现一个列表项切换到呈现另一个列表项的奇怪情况,而实际上它应该是一个全新的组件实例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 2017-10-11
      • 2018-07-26
      • 2020-09-02
      • 1970-01-01
      • 1970-01-01
      • 2020-07-17
      相关资源
      最近更新 更多