To understand the function of a key in React, you can start with the key value. The key value can be divided into three types: unvalued, indexed, and determined and unique

In the following code, key is undefined (math.random ())

Q: Does the color of span change to red when I click the button?

import React, { useState } from 'react'; Function App() {const [initMap, setInitMap] = useState([1,2,3,4]); Const handleClick = () = > {setInitMap ([1, 2, 3, 4]) var spanEle = document. The getElementsByTagName (" span "); Array.from(spanEle).map(it => it.style.color = 'red') } return ( <div className="App" id="app"> { initMap.map((it,index)  => <div key={Math.random()}><span>color</span></div>) } <button onClick={() => handleClick()}></button> </div> ); } export default App;Copy the code

The answer is: no

This problem involves the React rendering mechanism and the DIff algorithm

The official website has the following rules for diff:

  • When the element type changes, it is destroyed and rebuilt
  • Compare attributes when the element type is unchanged
  • When the component element type does not change, the child nodes are determined recursively by props
  • Recursively compare child nodes. When the child node is a list, check by the key and props. If the keys are consistent, update them. If the keys are inconsistent, destroy them and rebuild them

Analyze the above problems:

When the button is clicked, setInitMap([1,2,3,4]) renders, which generates a new virtual dom, but the span element retrieved is the previous one (because setInitMap is executed asynchronously), so the old and new dom are compared

Initmap.map ((it,index) => <div key={math.random ()}><span>color</span></div>Copy the code

In contrast to the fourth diff rule, React updates the real DOM based on the key. Key = {math.random ()}, the new and old DOM values are inconsistent, and the div is regenerated. We applied the red style to the element before the update, so the new element will not have the red style, so it will look like this

In the second case, the key value is an index value

The result of our analysis above is that the div element will be regenerated at render due to the change of key. What if the key stays the same after render? For example, change key to index

Q: Does this code change the color of span after button clicks?

return (
    <div className="App" id="app">
      <Spin spinning={spin}></Spin>
      {
        initMap.map((it,index) => <div key={index}><span>color</span></div>)
      }
      <button onClick={() => handleClick()}></button>
    </div>
  );
Copy the code

The answer:

React will only apply new attributes to span elements, but they still point to the original elements

Click on the front:After the click:

In the third case, the value of key is certain and unique:

In this example, the span color is changed by setting the key to index, but the React website does not recommend using index when using key

Modify the above code

Const [initMap, setInitMap] = useState([1,2,3,4]); Const handleClick = () => {setInitMap([3,2,1,4])} return (<div className="App" id=" App" > {initmap.map ((it,index) => < div key = {index} > < input type = "radio" / > < / div >)} {it} < button onClick = {() = > handleClick ()} > click < / button > < / div >). }Copy the code
  1. Select the button with a value of 3 at initialization time

  1. Click on the button

What we expect is that the selected button is still 3, but now the selected button is 1

Analysis:

  1. SetState then leads to render
  2. Div is not regenerated because its index is unchanged, and the input is not controlled by state or props, so the state of the element is unchanged
  3. Therefore, only it affected by state changes

If we want to achieve the desired effect, we need to set a unique and deterministic key

Test a:

{
   initMap.map((it) => <div key={it}><input type="radio" />{it}</div>)
}
Copy the code
  1. Select the third button when initializing

  1. Click on the button

This is the desired effect

Think about what happens if you set key to math.random (). Will the state of the button remain?

Click on the front:

After the click:

The state of radio is not preserved

React key function React key function React key function

React rendering conditions and real DOM manipulation are also described in the React code.

Extension 1: React render conditions

import './App.css'; import React, { useState } from 'react'; Function App() {const [initMap, setInitMap] = useState([1,2,3,4]); const [spin, setSpin] = useState(false); const handleClick = () => { setSpin(true); / / change of var spanEle = document. GetElementsByTagName (" span "); Array.from(spanEle).map(it => it.style.color = 'red') setSpin(false); } return (<div className="App" id=" App" >< Spin spinning={Spin}></Spin> {initmap.map ((it,index) => <div key={Math.random()}><span>{it}</span></div>) } <button onClick={() => handleClick()}></button> </div> ); } export default App;Copy the code

Test results are as follows before clicking:

After the click:

In this code, the div key is still math.random (), but the state of initMap has not changed, so it is not rerendered, and the div will not be destroyed and rebuilt

Extension 2: Whether you can manipulate the real DOM

In React, the virtual DOM is introduced to reduce the need to manipulate the real DOM. The real DOM element is a complex object that requires a lot of computation. In the above code, we are directly manipulating the DOM node to change the style, which is not desirable. React renders the page based on changes in state and props, so it is better to use state to control the page rendering

The modified code is as follows:

Function App() {const [initMap, setInitMap] = useState([1,2,3,4]); const [spin, setSpin] = useState(false); const [showColor, setShowColor] = useState(false); Const handleClick = () => {setInitMap([3,2,1,4]); setShowColor(true); } return ( <div className="App" id="app"> <Spin spinning={spin}> { initMap.map((it,index) => <div key={Math.random()}><span className={showColor && 'span-color'}>color</span></div>) } </Spin> <button onClick={() => HandleClick ()}> </button> </div>); }Copy the code

At this point, the span is a controlled component that controls the rendering of elements through the state of showColor

Click on the front:

After the click:

Using state to control rendering results in less code and results as expected

conclusion

  1. When using a key, ensure that the key is unique and deterministic. If the key has a value of math.random (), it may cause the component to be rebuilt, invalidating previous operations on the element
  2. When rendering the page, try not to manipulate the actual DOM and use state to update the page