Hvordan React-taster fungerer og sjove ting, du kan gøre med dem

React bruger keyattributten i sin afstemningsfase til at afgøre, hvilke elementer der kan genbruges til den næste gengivelse. De er vigtige for dynamiske lister. React sammenligner nøglerne til det nye element med de forrige taster og 1) monter komponenter med en ny nøgle 2) afmonter komponenter, hvis nøgler ikke bruges mere.

Mange React-udviklere har hørt det generelle råd, som du ikke skal bruge indexsom en nøgle. Men hvad kan der gå galt, når du bruger keys på en dårlig måde? Hvad kan vi ellers gøre, når vi leger med nøgler?

For en bedre forståelse, lad os overveje eksemplet med gengivelse af en liste over inputs. Når du klikker på en knap, indsætter vi et nyt element med tekst Frontforan på listen.

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 ( 
  • ); }}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 (
      {this.state.items.map((item, index) => ( ))}
    Add Item ); }}render(, document.getElementById("root"));

    Hvis du bruger indexsom en nøgle, sker følgende:

    CodeSandbox

    CodeSandbox er en online editor, der er skræddersyet til webapplikationer. codesandbox.io

    Hvad hvis en anden Itemmed tekst i Secondstedet for Frontindsættes bag på listen? Her er hvad der sker:

    1. Item is an uncontrolled component: Teksten, som brugeren skriver i sit inputfelt, gemmes somstate
    2. Et nyt dataelement { text: "Front" }indsættes i begyndelsen af ​​listedataene.
    3. Listen gengives igen med indeksværdien som key. Så de tidligere komponenter genanvendes til de to første dataelementer og får de korrekte rekvisitter Frontog First, men tilstanden opdateres ikke Item. Derfor beholder de to første komponentforekomster den samme tekst.
    4. En ny komponentforekomst oprettes til, key: 2fordi der ikke findes nogen tidligere matchende nøgle. Den udfyldes med det propssidste listeelement, der er Second.

    Et andet interessant punkt er de renderopkald, der sker. Elementet er a PureComponent, så det opdateres kun, når textprop (eller tilstand) ændres:

    rerendering Frontrerendering Firstrerendering SecondMounted Second

    Alle komponenter gengives igen. Dette sker, fordi elementet med key: 0genbruges til det første dataelement og modtager dets props, men det første dataelement er nu det nye Frontobjekt, der udløser a render. Det samme sker med de andre komponenter, fordi de gamle dataelementer nu alle flyttes ét sted.

    Så hvad er løsningen? Løsningen er let: Vi giver hvert listeoplysningselement en unik idgang efter oprettelsen (ikke på hver gengivelse!). Alle komponentforekomster matches med deres tilsvarende dataelement. De modtager det samme propssom før, og dette undgår en anden render.

    Lad os ignorere de ydelsesfordele, der kommer fra at bruge ids i dynamiske lister for nu. Eksemplet viser, at fejl, der er introduceret med nøgler, kun altid sker med hensyn til ukontrollerede komponenter , komponenter, der holder intern tilstand .

    Hvis vi omskriver Itemsom en kontrolleret komponent, er fejlen væk ved at flytte staten ud af den.

    Hvorfor? Igen, fordi fejlen genbruger en komponent til et andet dataelement. Derfor afspejlede den interne tilstand stadig tilstanden for det forrige dataelement , men rekvisitterne fra en anden . At gøre komponenten kontrolleret ved at fjerne dens tilstand fuldstændigt har vi ikke denne uoverensstemmelse længere. (Men der er stadig problemet med de unødvendige gengivelser.)

    Misbrug af nøgler til at rette ødelagte tredjepartskomponenter

    React behøver kun keys, når der matches flere elementer, så det er ikke nødvendigt at indstille en nøgle til et enkelt barn. Men det kan stadig være nyttigt at indstille en nøgle til en enkelt underordnet komponent.

    Hvis du ændrer nøglen, smider React hele komponenten (afmonterer den) og monterer en ny komponentforekomst på sin plads. Hvorfor kunne dette være nyttigt?

    Igen kommer vi tilbage til ukontrollerede komponenter . Nogle gange bruger du en tredjepartskomponent, og du kan ikke ændre dens kode for at gøre den kontrolleret. Hvis en komponent har en eller anden intern tilstand, og den er implementeret på en dårlig måde (for eksempel afledes tilstanden kun en gang i konstruktøren, men getDerivedStateFromProps/ componentWillReceivePropser ikke implementeret for at afspejle gentagne propsændringer i dens interne tilstand) , kan standard React-værktøjskassen ikke hjælpe dig her. Der er ingen forceRemount.

    Vi kan dog bare indstille en ny keypå denne komponent for at opnå den ønskede adfærd ved fuldstændig initialisering af en ny komponent. Den gamle komponent afmonteres, og en ny monteres med den nye propsinitialisering af state.

    TL; DR:

    Brug indexsom en nøgle kan:

    1. føre til unødvendige gengivelser
    2. introducere bugs, når listeelementerne er ukontrollerede komponenter, men stadig brugesprops

    Den keyegenskab kan bruges til at gennemtvinge en komplet remount af en komponent, der til tider kan være nyttige.

    Oprindeligt udgivet på cmichel.io