Reagált kötegelt frissítések

Az állapotfrissítések egyesítése egyetlen megjelenítési hívásban

A React.js kötegelt frissítések

Már tudja, hogy amikor frissíti az összetevő állapotát, a React eltérő algoritmusa észleli a virtuális DOM változásait, és megjeleníti az összetevőt a valódi DOM -ban. De valóban ez történik minden egyes állapotfrissítésnél? Vagy a React lehetőséget biztosít a frissítések kötegelt összegyűjtésére, hogy több állapotmutáció egyetlen renderelési hívássá egyesüljön?

A szintetikus események lehetővé teszik a kötegek frissítését

A React 17 és régebbi mechanizmusok biztosítják a frissítések kötegelését. Tényleg nem kell sokat gondolkodnia a kódolás során, de annak ismerete, hogy a React hogyan optimalizálhatja a kódot, nagyszerű tanulság.

Íme, mi történik.

  • visszahíváson belül több állapotmutációt hívnak meg
  • ha a visszahívás szintetikus eseményhez van csatolva, a React kötegeli ezeket a mutációkat
  • mutációk csoportosításakor csak egyetlen render-hívás történik
  • ellenkező esetben minden mutáció új megjelenítéshez vezet

A kötegelés lehetővé tétele érdekében az állapotmutációkat egy szintetikus React-eseményen belül kell meghívni. Gyors emlékeztetőül: a szintetikus React események alapvetően csak a natív HTML-események köré épülnek, hogy minden böngészőben ugyanazt a funkciót biztosítsák. Minden szintetikus eseménykezelőt közvetlenül hozzá lehet adni egy alkatrészhez támasztóként.

Hogy mindezt működés közben lássa, íme egy példakód, amely lehetővé tenné a React számára, hogy az összes állapotmutációt egyetlen megjelenítésbe egyesítse, mutációnként egy renderelés helyett.

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>
  );
}

Kötegelt frissítések a React 18 és újabb verzióihoz

A React következő verziójával (legalábbis amíg ezt írom) a kötegelési mechanizmus sokkal jobban javul. Ahelyett, hogy csak szintetikus eseményekben lenne lehetséges, más típusú visszahívások is használhatók lesznek.

  • időtúllépések
  • ígéretek
  • natív eseménykezelők

Ez a módosítás nagy valószínűséggel az alkalmazás jobb teljesítményéhez vezet, mivel kevesebb megjelenítés történik automatikusan.

Kerülje a kötegelt frissítéseket a React 18 -ban és később

A React 18 -tól kezdve lehetősége lesz arra, hogy minden állapotmutációval kifejezetten új megjelenítést indítson el, elkerülve ezzel a kötegelt frissítést. Ezt valószínűleg csak szélső esetekben fogják használni, de ennek ellenére érdekes tudni.

//  
// 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
}