当前位置: 首页 > 工具软件 > React Toolbox > 使用案例 >

react 右键_React键如何工作以及您可以通过它们完成的有趣事情

孔磊
2023-12-01

react 右键

by Christoph Michel

克里斯托夫·米歇尔(Christoph Michel)

React键如何工作以及您可以通过它们完成的有趣事情 (How React keys work and fun things you can do with them)

React uses the key attribute during its reconciliation phase to decide which elements can be reused for the next render. They are important for dynamic lists. React will compare the keys of the new element with the previous keys and 1) mount components having a new key 2) unmount components whose keys are not used anymore.

对帐阶段 ,React使用key属性来决定哪些元素可用于下一个渲染。 它们对于动态列表很重要。 React会将新元素的键与先前的键进行比较,并且1)具有新键的安装组件2)不再使用其键的卸载组件。

Many React developers have heard the general advice that you should not use index as a key. But what exactly can go wrong when using keys in a bad way? What else can we do when we play around with keys?

许多React开发人员已经听到了一般性建议,即您不应使用index作为键 。 但是,当以不好的方式使用key时,究竟会出什么问题呢? 当我们玩弄钥匙时还能做什么?

For a better understanding, let’s consider the example of rendering a list of inputs. When clicking a button, we will insert a new item with text Front to the front of the list.

为了更好地理解,让我们考虑呈现input s列表的示例 。 单击一个按钮时,我们将在列表的前面插入一个文本为Front的新项目。

import React from "react";import { render } from "react-dom";class Item extends React.PureComponent {  state = {    text: this.props.text  };  onChange = event => {    this.setState({      text: event.target.value    });  };  componentDidMount() {    console.log("Mounted ", this.props.text);  }  componentWillUnmount() {    console.log("Unmounting ", this.props.text);  }  render() {    console.log("rerendering ", this.props.text);    const { text } = this.state;    return (      <li>        <input value={text} onChange={this.onChange} />      </li>    );  }}class App extends React.Component {  state = {    items: [      {        text: "First",        id: 1      },      {        text: "Second",        id: 2      }    ]  };  addItem = () => {    const items = [{ text: "Front", id: Date.now() }, ...this.state.items];    this.setState({ items });  };  render() {    return (      <div>        <ul>          {this.state.items.map((item, index) => (            <Item {...item} key={index} />          ))}        </ul>        <button onClick={this.addItem}>Add Item</button>      </div>    );  }}render(<App />, document.getElementById("root"));

If you use index as a key, the following happens:

如果使用index作为键,则会发生以下情况:

CodeSandboxCodeSandbox is an online editor tailored for web applications.codesandbox.io

CodeSandbox CodeSandbox是为Web应用程序量身定制的在线编辑器。 codesandbox.io

What if another Item with text Second instead of Front is inserted at the back of the list? Here's what happens:

如果在列表的后面插入另一个文本为Second而不是Front Item怎么办? 这是发生了什么:

  1. Item is an uncontrolled component: The text the user writes into its input field is stored as state

    Item is an uncontrolled component :用户写入其input字段的文本存储为state

  2. A new data item { text: "Front" } is inserted to the beginning of the list data.

    新数据项{ text: "Front" }插入到列表数据的开头。

  3. The list is re-rendered with the index value as key. So the previous components are re-used for the first two data items and are given the correct props Front and First, but the state is not updated in Item. That's why the first two component instances keep the same text.

    使用索引值作为key重新呈现该列表。 因此,先前的组件被重新用于前两个数据项,并被赋予正确的道具FrontFirst ,但状态未在Item更新。 这就是为什么前两个组件实例保留相同文本的原因。

  4. A new component instance is created for key: 2 because no previous matching key is found. It is filled with the props of the last list data item which is Second.

    key: 2创建了新的组件实例,因为未找到先前的匹配键。 它填充了最后一个列表数据项props Second

Another interesting point is the render calls that happen. Item is a PureComponent, so it only updates when the text prop (or state) changes:

另一个有趣的地方是发生的render调用。 Item是PureComponent ,因此仅在text PureComponent (或状态)更改时才更新:

rerendering  Frontrerendering  Firstrerendering  SecondMounted  Second

All components are re-rendered. This happens because the element with key: 0 is reused for the first data item and receives its props, but the first data item is now the new Front object, triggering a render. The same happens with the other components, because the old data items are now all shifted by one place.

所有组件都重新渲染。 发生这种情况的原因是, key: 0的元素被第一个数据项重用并接收其props ,但是第一个数据项现在是新的Front对象,从而触发了render 。 其他组件也会发生同样的情况,因为现在所有旧数据项都移位了一位。

So what’s the fix? The fix is easy: we give each list data item a unique id one time upon creation (not on each render!). All components instances will be matched with their corresponding data item. They receive the same props as before, and this avoids another render.

那么解决方法是什么? 该修补程序很简单:我们独特的给每个列表数据项id同一时间在创建时 (而不是在每个渲染!)。 所有组件实例将与其对应的数据项匹配。 他们收到与以前相同的props ,从而避免了其他render

Let’s ignore the performance benefits that come from using ids in dynamic lists for now. The example shows that bugs introduced by keys only ever happen with regards to uncontrolled components, components that keep internal state.

现在让我们忽略在动态列表中使用id带来的性能优势。 该示例表明, 键引入的错误只会发生在不受控制的组件 (保持内部状态的组件)方面。

If we rewrite Item as a controlled component, by moving the state out of it, the bug is gone.

如果我们将Item重写为受控组件,则通过将其移出状态,该错误将消失。

Why? Again, because the bug was reusing a component for a different data item. Therefore, the internal state still reflected the state of the previous data item, but the props of a different one. Making the component controlled, by removing its state completely, we don’t have this discrepancy anymore. (But there’s still the issue with the unnecessary re-renders.)

为什么? 再一次,因为该错误正在将组件重新用于其他数据项。 因此,内部状态仍然反映了前一个数据项的状态 ,但反映了另一个 数据项道具 。 通过完全删除组件的状态来使组件受控制,我们不再存在这种差异。 (但是仍然存在不必要的重新渲染的问题。)

滥用密钥来修复损坏的第三方组件 (Abusing keys to fix broken third-party components)

React only needs keys when matching several elements, so setting a key on a single child is not needed. But it can still be useful to set a key on a single child component.

当匹配多个元素时,React仅需要key ,因此不需要在单个子代上设置键。 但是在单个子组件上设置键仍然有用。

If you change the key, React will throw away the whole component (unmount it), and mount a new component instance in its place. Why could this be useful?

如果您更改密钥,React将丢弃整个组件(将其卸载),并在其位置安装一个新的组件实例。 为什么这会有用?

Again, we’re coming back to uncontrolled components. Sometimes, you’re using a third-party component and you cannot modify its code to make it controlled. If a component has some internal state and it’s implemented in a bad way (for example, the state is derived only once in the constructor, but getDerivedStateFromProps / componentWillReceiveProps is not implemented to reflect reoccurring props changes in its internal state), the standard React toolbox cannot help you here. There is no forceRemount.

再次,我们回到不受控制的组件 。 有时,您正在使用第三方组件,并且无法修改其代码以使其受到控制。 如果一个组件具有某种内部状态并且以不好的方式实现(例如,状态在构造函数中仅被导出一次 ,但是没有实现getDerivedStateFromProps / componentWillReceiveProps反映内部状态中 getDerivedStateFromProps 发生的props更改) ,则标准React工具箱在这里无法帮助您。 没有forceRemount

However, we can just set a new key on this component to achieve the desired behavior of completely initializing a new component. The old component will be unmounted, and a new one will be mounted with the new props initializing the state.

但是,我们可以在该组件上设置一个新key ,以实现完全初始化新组件所需的行为。 旧的组件将被卸载,并且一个新的将被安装的新props初始化state

TL; DR: (TL;DR:)

Using index as a key can:

使用index作为键可以:

  1. lead to unnecessary re-renders

    导致不必要的重新渲染
  2. introduce bugs when the list items are uncontrolled components but still use props

    当列表项是不受控制的组件但仍使用props时引入错误

The key property can be used to force a complete remount of a component, which can sometimes be useful.

key属性可用于强制完全重新安装组件,这有时很有用。

Originally published at cmichel.io

最初发布于cmichel.io

翻译自: https://www.freecodecamp.org/news/react-fun-with-keys-68f4c8c36f3e/

react 右键

 类似资料: