Αντιδράστε σε μαζικές ενημερώσεις

Πώς να συνδυάσετε ενημερώσεις κατάστασης σε μία μόνο κλήση απόδοσης

Μαζικές ενημερώσεις του React.js

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

Τα συνθετικά συμβάντα επιτρέπουν ενημερώσεις παρτίδων

Το React 17 και κάτω παρέχει έναν μηχανισμό για τη συλλογή αυτών των ενημερώσεων. Πραγματικά δεν χρειάζεται να το σκέφτεστε πολύ κατά την κωδικοποίηση, αλλά το να γνωρίζετε πώς το React μπορεί να βελτιστοποιήσει τον κώδικά σας είναι παρόλα αυτά μια εξαιρετική μάθηση.

Ιδού τι συμβαίνει.

  • πολλαπλές μεταλλάξεις κατάστασης καλούνται μέσα σε μια επανάκληση
  • εάν η επανάκληση επισυνάπτεται σε ένα συνθετικό συμβάν, το React θα συγκεντρώσει αυτές τις μεταλλάξεις
  • όταν συγκεντρώνονται μεταλλάξεις, πραγματοποιείται μόνο μία μόνο κλήση απόδοσης
  • διαφορετικά, κάθε μετάλλαξη οδηγεί σε μια νέα απόδοση

Για να επιτραπεί η παρτίδα, οι μεταλλάξεις της κατάστασής σας πρέπει να κληθούν μέσα σε ένα συνθετικό συμβάν React. Ως γρήγορη υπενθύμιση, τα συνθετικά συμβάντα React είναι βασικά απλώς ένα περιτύλιγμα γύρω από εγγενή συμβάντα HTML για να παρέχουν την ίδια λειτουργικότητα σε όλα τα προγράμματα περιήγησης. Κάθε συνθετικός χειριστής συμβάντων μπορεί να παρασχεθεί απευθείας σε ένα στοιχείο ως υποστήριξη.

Για να τα δείτε όλα σε δράση, εδώ είναι ένα παράδειγμα κώδικα που θα επιτρέψει στο React να συνδυάσει όλες τις μεταλλάξεις κατάστασης σε μία απόδοση, αντί για μία απόδοση ανά μετάλλαξη.

function Component() {
  const [id, setId] = useState(0);
  const [date, setDate] = useState(new Date());
  const [random, setRandom] = useState(Math.random());

  // A lame callback, but it's just for
  // the demo. Note that clicking on the
  // button will only lead to a single
  // re-render!
  //
  // This is b/c the callback is provided to
  // 'onClick', a synthetic event.
  const onButtonClick = () => {
    setDate(new Date());
    setId(prevId => prevId + 1);
  }
  
  console.log("Render:", id, date);

  return (
    <div>
      <button 
        onClick={onButtonClick}>
        Update state
      </button>
    </div>
  );
}
//
// Almost the same as the previous
// example, but this time w/o
// a batched upate call.
//

function Component() {
  const [id, setId] = useState(0);
  const [date, setDate] = useState(new Date());
  const [random, setRandom] = useState(Math.random());

  // No batching, as the state
  // mutations happend inside
  // a setTimeout - even though
  // the timeout is inside a 
  // synthetic event.
  const onButtonClick = () => {
    setTimeout(() => {
      setDate(new Date());
      setId(prevId => prevId + 1);
    }, 0);
  }
  
  console.log("Render:", id, date);

  return (
    <div>
      <button 
        onClick={onButtonClick}>
        Update state
      </button>
    </div>
  );
}

Μαζικές ενημερώσεις για το React 18 και νεότερες εκδόσεις

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

  • τάιμ άουτ
  • υποσχέσεις
  • εγγενείς χειριστές εκδηλώσεων

Αυτή η αλλαγή πιθανότατα θα οδηγήσει σε καλύτερη απόδοση της εφαρμογής σας, καθώς λιγότερη απόδοση θα γίνει αυτόματα.

Αποφυγή μαζικών ενημερώσεων στο React 18 και νεότερες εκδόσεις

Ξεκινώντας από το React 18, θα έχετε την επιλογή να ενεργοποιήσετε ρητά μια νέα απόδοση με κάθε μετάλλαξη κατάστασης, αποφεύγοντας συνεπώς μια μαζική ενημέρωση. Αυτό πιθανότατα θα χρησιμοποιηθεί μόνο σε ακραίες περιπτώσεις, αλλά παρόλα αυτά είναι ενδιαφέρον να γνωρίζουμε.

//  
// This example is almost
// 1:1 from Dan Abramov's
// example.
//
// Use 'flushSync' from the
// 'react-dom'-package.
import { flushSync } from 'react-dom'; 

function handleClick() {
  flushSync(() => {
    setId(prevId => prevId + 1);
  });
  // React has updated the DOM by now
  flushSync(() => {
    setDate(new Date());
  });
  // React has updated the DOM by now
}

Προτάσεις

Σχετικά

Προσάρτημα

Γλώσσες