Πώς λειτουργούν τα πλήκτρα React και διασκεδαστικά πράγματα που μπορείτε να κάνετε μαζί τους

Το React χρησιμοποιεί το keyχαρακτηριστικό κατά τη φάση συμφιλίωσης για να αποφασίσει ποια στοιχεία μπορούν να επαναχρησιμοποιηθούν για την επόμενη απόδοση. Είναι σημαντικά για δυναμικές λίστες. Το React θα συγκρίνει τα πλήκτρα του νέου στοιχείου με τα προηγούμενα πλήκτρα και 1) εξαρτήματα προσάρτησης με νέο κλειδί 2) αποσυναρμολόγηση στοιχείων των οποίων τα κλειδιά δεν χρησιμοποιούνται πλέον.

Πολλοί προγραμματιστές του React έχουν ακούσει τις γενικές συμβουλές που δεν πρέπει να χρησιμοποιείτε indexως κλειδί. Αλλά τι ακριβώς μπορεί να πάει στραβά όταν χρησιμοποιείτε το keys με κακό τρόπο; Τι άλλο μπορούμε να κάνουμε όταν παίζουμε με κλειδιά;

Για καλύτερη κατανόηση, ας εξετάσουμε το παράδειγμα της απόδοσης μιας λίστας input. Κάνοντας κλικ σε ένα κουμπί, θα εισάγουμε ένα νέο στοιχείο με κείμενο 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 ( 
  • ); }}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"));

    Εάν χρησιμοποιείτε indexως κλειδί, συμβαίνουν τα εξής:

    CodeSandbox

    Το CodeSandbox είναι ένας διαδικτυακός επεξεργαστής προσαρμοσμένος για εφαρμογές Ιστού. κώδικεςandbox.io

    Τι γίνεται αν ένα άλλο Itemμε κείμενο Secondαντί Frontεισάγεται στο πίσω μέρος της λίστας; Να τι συμβαίνει:

    1. Item is an uncontrolled component: Το κείμενο που γράφει ο χρήστης στο inputπεδίο του αποθηκεύεται ωςstate
    2. Ένα νέο στοιχείο δεδομένων { text: "Front" }εισάγεται στην αρχή των δεδομένων της λίστας.
    3. Η λίστα αποδίδεται εκ νέου με την τιμή ευρετηρίου ως key. Έτσι, τα προηγούμενα στοιχεία επαναχρησιμοποιούνται για τα δύο πρώτα στοιχεία δεδομένων και έχουν τα σωστά στηρίγματα Frontκαι First, αλλά η κατάσταση δεν ενημερώνεται στο Item. Γι 'αυτό οι δύο πρώτες συνιστώσες εμφανίζουν το ίδιο κείμενο.
    4. Δημιουργείται μια νέα παρουσία συστατικών key: 2επειδή δεν βρέθηκε προηγούμενο κλειδί αντιστοίχισης. Είναι γεμάτο με το propsτελευταίο στοιχείο δεδομένων λίστας που είναι Second.

    Ένα άλλο ενδιαφέρον σημείο είναι οι renderκλήσεις που συμβαίνουν. Το στοιχείο είναι ένα PureComponent, οπότε ενημερώνεται μόνο όταν textαλλάζει το στήριγμα (ή κατάσταση):

    rerendering Frontrerendering Firstrerendering SecondMounted Second

    Όλα τα στοιχεία εκ νέου αποδίδονται. Αυτό συμβαίνει επειδή το στοιχείο με key: 0επαναχρησιμοποιείται για το πρώτο στοιχείο δεδομένων και το λαμβάνει props, αλλά το πρώτο στοιχείο δεδομένων είναι τώρα το νέο Frontαντικείμενο, ενεργοποιώντας ένα render. Το ίδιο συμβαίνει και με τα άλλα στοιχεία, επειδή τα παλιά στοιχεία δεδομένων έχουν πλέον μετατοπιστεί από ένα μέρος.

    Λοιπόν, ποια είναι η λύση; Η επιδιόρθωση είναι εύκολη: δίνουμε σε κάθε στοιχείο δεδομένων λίστας μια μοναδική idφορά κατά τη δημιουργία (όχι σε κάθε απόδοση!). Όλες οι παρουσίες στοιχείων θα αντιστοιχιστούν με το αντίστοιχο στοιχείο δεδομένων τους. Λαμβάνουν το ίδιο propsόπως πριν, και αυτό αποφεύγει ένα άλλο render.

    Ας αγνοήσουμε τα οφέλη απόδοσης που προέρχονται από τη χρήση του ids σε δυναμικές λίστες προς το παρόν. Το παράδειγμα δείχνει ότι τα σφάλματα που εισάγονται από κλειδιά συμβαίνουν ποτέ μόνο σε σχέση με μη ελεγχόμενα στοιχεία , στοιχεία που διατηρούν εσωτερική κατάσταση .

    Εάν ξαναγράψουμε Itemως ελεγχόμενο στοιχείο, μετακινώντας την κατάσταση από αυτό, το σφάλμα εξαφανίζεται.

    Γιατί; Και πάλι, επειδή το σφάλμα επαναχρησιμοποίησε ένα στοιχείο για ένα διαφορετικό στοιχείο δεδομένων. Επομένως, η εσωτερική κατάσταση αντικατοπτρίζει ακόμα την κατάσταση του προηγούμενου στοιχείου δεδομένων , αλλά τα στηρίγματα ενός διαφορετικού . Κάνοντας το στοιχείο ελεγχόμενο, αφαιρώντας πλήρως την κατάστασή του, δεν έχουμε πλέον αυτήν την ασυμφωνία. (Αλλά εξακολουθεί να υπάρχει το πρόβλημα με τις περιττές επανεκδόσεις.)

    Κατάχρηση κλειδιών για τη διόρθωση σπασμένων στοιχείων τρίτων

    Η αντίδραση χρειάζεται μόνο keyόταν ταιριάζει με πολλά στοιχεία, οπότε δεν απαιτείται ρύθμιση ενός κλειδιού σε ένα μόνο παιδί. Ωστόσο, μπορεί να είναι χρήσιμο να ορίσετε ένα κλειδί σε ένα στοιχείο παιδιού.

    Εάν αλλάξετε το κλειδί, το React θα πετάξει ολόκληρο το στοιχείο (αποσυναρμολόγηση) και θα τοποθετήσει μια νέα παρουσία στοιχείου στη θέση του. Γιατί θα μπορούσε αυτό να είναι χρήσιμο;

    Και πάλι, επιστρέφουμε σε ανεξέλεγκτα στοιχεία . Μερικές φορές, χρησιμοποιείτε ένα στοιχείο τρίτου μέρους και δεν μπορείτε να τροποποιήσετε τον κώδικά του για να το ελέγξετε. Εάν ένα στοιχείο έχει κάποια εσωτερική κατάσταση και εφαρμόζεται με κακό τρόπο (για παράδειγμα, η κατάσταση προέρχεται μόνο μία φορά στον κατασκευαστή, αλλά getDerivedStateFromProps/ componentWillReceivePropsδεν εφαρμόζεται για να αντικατοπτρίζει τις επαναλαμβανόμενες propsαλλαγές στην εσωτερική του κατάσταση) , η τυπική εργαλειοθήκη React δεν μπορεί να σας βοηθήσει εδώ. Δεν υπάρχει forceRemount.

    Ωστόσο, μπορούμε απλά να ορίσουμε ένα νέο keyσε αυτό το στοιχείο για να επιτύχουμε την επιθυμητή συμπεριφορά της πλήρους αρχικοποίησης ενός νέου στοιχείου. Το παλιό στοιχείο θα αποσυνδεθεί και ένα νέο θα τοποθετηθεί με το νέο propsαρχικοποίηση του state.

    TL; DR:

    Η χρήση indexως κλειδιού μπορεί:

    1. οδηγούν σε περιττές εκδόσεις
    2. εισαγάγετε σφάλματα όταν τα στοιχεία της λίστας είναι ανεξέλεγκτα στοιχεία αλλά εξακολουθούν να χρησιμοποιούνταιprops

    Η keyιδιότητα μπορεί να χρησιμοποιηθεί για να αναγκάσει ένα πλήρες remount ενός στοιχείου, το οποίο μερικές φορές μπορεί να είναι χρήσιμο.

    Αρχικά δημοσιεύθηκε στο cmichel.io