编程知识 cdmana.com

What's the use of the key in react / Vue? You will know after reading this article! (with demo code)

There are many blogs on the Internet about ,React、Vue Inside key, And Virtual DOM And DOM diff of ,  Can be used to uniquely identify DOM node , Improve diff efficiency , At such a time .

That's roughly right , however , Most of them are vague , It's like reciting the answers .

How to follow suit ? Why use array subscripts as key yes “ Anti pattern ”? I talked a lot , Can I see for sure ,show me the code?

This article takes React For example , Try a little planing , But not to the bottom , With enough help to understand .

1. VNode diff

First introduced Virtual DOM node ( Short for Virtual Node, VNode) How to create .

In reality React Almost all projects use JSX, and JSX Not directly , It needs to be done first babel Translate it into js Code , such as :

<div className="content">Hello world!</div>

Will be compiled into

React.createElement("div", {
    className: "content"
}, "Hello world!");

Click here to see the online compilation

therefore , Just call  React.createElement This static method , You can create a VNode.

No need to go deep VNode The specific data structure of , Just look at the parameters of this factory method , We can know DOM diff  to the end diff What did you learn .

according to React Official documents , This method can receive ≥3 Parameters :

  • The first parameter is type, Specify the node type , If it is HTML Native node , So it's going to be a string , such as "div"; If it is React Components , Then it would be a class or function;
  • The second parameter is props, It's an object or something null. For example, in the previous example ,div On the label "className" Attributes are added here ;
  • Third ( And fourth , The fifth ,……) The parameters are childNode, The children of this node . In the previous example ,div The child node of is a node whose content is "Hello world!" Of TextNode

It's a drop ,DOM diff  Specifically diff Things that are , These are the parameters . Why can't there be anything else ? Because that doesn't fit React Design concept of :Data => UI One way mapping .

2.  Dynamic list of diff Predicament

We know React Calling setState Trigger render when , The old and the new Virtual DOM compare , Strive to complete the new project with the least cost DOM Rendering tasks .

Combined with the parameters mentioned above , The specific comparison process is roughly like this :

  • Compare first type. If type Different , There's nothing to say , Directly destroy and re create One ; If type identical , Then further to see :
  • Second, compare props, If there is a change , Let's take the changing part update; If it doesn't change , Then look back :
  • Finally, compare the child nodes , similarly , If there are changes, just update, Do nothing without change

This is in DOM It's easy to use when the structure is fixed , But when we want to start from a list Map out the list 、 And this list When the items in are subject to change at any time , There's a little bit of trouble .

for instance , Original list That's true :

[
  {name: 'Smith', job: 'Engineer'},
  {name: 'Alice', job: 'HR'},
  {name: 'Jenny', job: 'Designer'}
]

then ,Jenny Moved to the front , that Smith and Alice It's moved back accordingly , Turned into

[
  {name: 'Jenny', job: 'Designer'},
  {name: 'Smith', job: 'Engineer'},
  {name: 'Alice', job: 'HR'}
]

about React Come on , If it doesn't know these three nodes “ Originally ” Who is it? , Just check one by one according to the corresponding position , You will find that every node has changed :

  • Smith => Jenny
  • Alice => Smith
  • Jenny => Alice

therefore React Come to the conclusion : All nodes in the list , It all needs to be update, To render !

wait a moment ! Is there a better way ?

3.  With the help of key broken

If ,React“ know ” These three nodes “ Originally ” Who is it? , Then things will be much easier :

No need to update any DOM node , just hold Jenny Take off the corresponding node , And then insert it into the new location , Finished .

but React How do you know who is who ?

This requires us developers to tell it manually , therefore key Appearance. .

Doing it DOM diff when , If two of the same parent components VNode Have the same key, Will be treated as the same node , If React According to this, it can be concluded that , The ranking of this node in the list has changed , It'll be like that , Conduct “ Take off - Insert ” Handle .

To prove it , Bright code !

First of all, the last one intentionally made bug Version of :

class App extends React.Component {
  state = {
    list: [0, 1, 2]
  }

  add() {
    const list = this.state.list;
    this.setState({ list: [list.length, ...list] });
  }

  render() {
    return (
      <div className="App">
        <button onClick={() => this.add()}>Input sth below, then click me</button>
        <ul>
          {
// Be careful : It's used here on purpose index As key, trigger bug
this.state.list.map((item, index) => ( <li key={index}> <span>Item-{item}</span> <input type="text" /> </li> ) ) } </ul> </div> ); } }

ReactDOM.render(
<App />,
document.getElementById('root')
);

It can be used create-react-app Start a project , Try this code locally . The demonstration effect is as follows , First, enter some... In the second line text box 1:

then , Click the button above , Will find ……

Entered a string of 1 The text box of is not followed by Item-1 go , It's staying in “ In situ ”!

This is it. Use the array subscript for key A typical example of triggering bug. The reason is in the new list Item-0 And from the original list Item-1 Have the same key, By React As the same node , So it's just “ In situ ” Updated child nodes ( Text ), It doesn't move the position of the node .

And this bug The clever thing about it is that it uses <input>, It can be VNode Of type、props、children On the premise of no change , Changed by user behavior ( Input content ), So that we can see the position of the node intuitively . thank React The government provided this ingenious case.

good , Now let's fix this bug.

The fix is simple : hold key={index} Change to key={item} That's it .

preservation , Refresh and try again , We can get it :

this time , The correspondence is right ,React Correctly identified 3 An old node , Insert the new node directly at the beginning of the list , And the old nodes don't change .

 

The end of the article . See here , You should understand key What's the point , And why index It's not suitable to do key Is that right !

版权声明
本文为[Duhu of western regions in Tang Dynasty]所创,转载请带上原文链接,感谢
https://cdmana.com/2021/04/20210422000405096p.html

Scroll to Top