Kodokon kodokon.com

पर्दे के पीछे: reconciliation, batching, concurrent rendering

जानें कि Fiber कैसे tree को reconcile करता है, updates को batch करता है, और rendering के काम को बीच में रोका जा सकने योग्य बनाता है।

11 मिनट · 3 प्रश्न

इस पाठ को Kodokon में खोलें

React 16 से, आंतरिक इंजन को Fiber कहा जाता है: आपके tree का हर element एक fiber node द्वारा दर्शाया जाता है, जो काम की एक इकाई है। React असल में दो trees बनाए रखता है (एक double-buffering तकनीक): current tree, जो स्क्रीन पर जो है उसे दर्शाता है, और workInProgress tree, जो rendering के दौरान बनाया जाता है। काम दो अलग-अलग चरणों में होता है: render phase (आपके components को call करना, अंतर की गणना करना), जो बीच में रोका जा सकने योग्य और दोबारा चलाए जा सकने योग्य है, फिर commit phase (DOM पर बदलाव लागू करना, effects चलाना), जो हमेशा synchronous और बीच में न रोका जा सकने योग्य होता है। Reconciliation दो heuristics पर निर्भर करता है जो तुलना की लागत को linear तक ले आते हैं: अगर किसी दिए गए स्थान पर element का type बदलता है, तो React पूरे subtree को नष्ट कर देता है और उसे फिर से बनाता है, state सहित; lists के लिए, key prop React को दो renders के बीच elements का मिलान करने देता है।

JSX
function List({ items }) {
  return (
    <ul>
      {items.map((item) => (
        <li key={item.id}>
          <input defaultValue={item.label} />
        </li>
      ))}
    </ul>
  );
}
// With key={index}, deleting the first item
// would shift the content of the remaining inputs.
एक स्थिर key हर row की state और DOM को सुरक्षित रखती है।

दूसरा मूलभूत तंत्र: batching। जब एक ही context के भीतर कई state updates ट्रिगर होते हैं, तो React उन्हें एकल render में समूहित कर देता है। React 18 से पहले, यह समूहन केवल React event handlers के भीतर ही काम करता था; createRoot के बाद से, यह हर जगह अपने आप होता है: timers, promises, native listeners। यही कारण है कि setState के तुरंत बाद state पढ़ने पर पुराना मान मिलता है: update शेड्यूल किया जाता है, लागू नहीं किया जाता।

JSX
function handleTick() {
  setCount((c) => c + 1);
  setFlag((f) => !f);
  // React 18: a single render, even here.
}

setTimeout(handleTick, 100);
// Before React 18, this timer would trigger
// two successive renders.
Automatic batching अब हर context को कवर करता है।

Concurrent rendering तर्क को और आगे ले जाता है: render phase को बीच में रोका, फिर से शुरू किया, या यहाँ तक कि छोड़कर दोबारा शुरू किया जा सकता है, अगर कोई अधिक ज़रूरी update आ जाए। React updates को प्राथमिकता के अनुसार क्रमबद्ध करता है (lanes): एक keystroke ज़रूरी है, startTransition से चिह्नित एक list filter नहीं। इसका सीधा परिणाम: आपके component functions शुद्ध (pure) होने चाहिए, क्योंकि React उन्हें बिना परिणाम commit किए कई बार call कर सकता है। एक और edge case: बीच में रोके जा सकने योग्य render के दौरान पढ़ा गया कोई external store (Redux, Zustand, कोई घर का बना singleton) render के बीच में बदल सकता है, जिससे एक असंगत interface बनता है जिसे tearing कहते हैं। useSyncExternalStore API इस समस्या को store बदलने पर एक synchronous render को मजबूर करके हल करता है।

JAVASCRIPT
import { useSyncExternalStore } from 'react';

function useWindowWidth() {
  return useSyncExternalStore(
    (notify) => {
      window.addEventListener('resize', notify);
      return () =>
        window.removeEventListener('resize', notify);
    },
    () => window.innerWidth
  );
}
बिना tearing के जोखिम के किसी external store को पढ़ना।

ज्ञान जांच

सुनिश्चित करें कि आपको इस पाठ के मुख्य बिंदु याद हैं।

  1. Reconciliation के दौरान, अगर कोई <div> element उसी स्थान पर <span> बन जाता है तो React क्या करता है?
    • यह children को रखते हुए tag को update कर देता है
    • यह पूरे subtree को नष्ट कर देता है, state सहित, और उसे फिर से बनाता है
    • यह निर्णय लेने से पहले children की पुनरावर्ती (recursively) तुलना करता है
    • यह एक reconciliation error फेंकता है
  2. React 18 और createRoot के साथ, किसी setTimeout के भीतर दो setState calls कितने renders ट्रिगर करती हैं?
    • दो, क्योंकि batching केवल React events पर लागू होता है
    • बस एक, automatic batching की बदौलत
    • शून्य, events के बाहर के updates को अनदेखा कर दिया जाता है
  3. Concurrent mode में React के काम का कौन-सा phase बीच में रोका जा सकने योग्य है?
    • केवल commit phase
    • केवल render phase
    • दोनों phases
    • कोई नहीं, React पूरी तरह synchronous रहता है