javascript - React key 如何工作?

标签 javascript html reactjs virtual-dom

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 tags a, 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/

相关文章:

javascript - 是否有任何环境可以实现新的自定义元素规范?

javascript - 整个 html 文档的 Backbone js View

node.js - Next.js - 图像不是 'defined"

reactjs - Google Firebase Auth 在 Netlify 上失败,但在本地服务器上工作

reactjs - React Typescript 自定义 Hook : Property 'prop_name' does not exist on type '{}'

javascript - 如何使用 Javascript 每 1 秒更改一次字符串

javascript - 什么是 gr :get:User in Facebook Graph Api? 达到应用程序限制错误

javascript - 从打印预览中删除输入框

c# - 如何重新打开纯 CSS3 模态对话框

css - 在移动 chrome/safari 中隐藏输入 [类型 ="month"] 清除按钮