Kodokon kodokon.com

Context: prop drilling के बिना साझा करना

context का उपयोग करके प्रॉप drilling के बिना डेटा को इधर-उधर पहुँचाएं, और साथ ही इसके re-renders तथा सीमाओं को नियंत्रण में रखें।

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

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

Prop drilling उन props को कहते हैं जो तीन या चार मध्यवर्ती कंपोनेंट से होकर गुज़रते हैं बिना वहाँ उपयोग हुए, सिर्फ़ पेड़ के किसी पत्ते तक पहुँचने के लिए। वे जिस भी परत को पार करते हैं वह ऐसे डेटा से जुड़ जाती है जिसकी उसे परवाह नहीं है। Context इस परिवहन समस्या को हल करता है: createContext चैनल बनाता है, एक provider एक मान प्रकाशित करता है, और useContext इसे किसी भी descendant से पढ़ता है। यह बारीकी याद रखें: context state को परिवहन करता है, इसे प्रबंधित नहीं करता - मान अब भी एक कंपोनेंट में रहता है, यहाँ provider में।

JSX
import { createContext, useMemo, useState } from "react";

const ThemeContext = createContext(null);

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("dark");
  const value = useMemo(
    () => ({ theme, setTheme }),
    [theme]
  );

  return (
    <ThemeContext.Provider value={value}>
      {children}
    </ThemeContext.Provider>
  );
}
प्रकाशित मान को memoize किया जाता है ताकि उसका reference स्थिर रहे।

जब provider का मान बदलता है, तो सभी consumers फिर से render होते हैं, यहाँ तक कि गहराई में nested वाले भी - और React.memo उनकी रक्षा नहीं करता, क्योंकि यह props की तुलना करता है, context की नहीं। क्लासिक जाल स्थिति को और बिगाड़ देता है: value={{ theme, setTheme }} लिखना provider के हर render पर एक नई object बनाता है, इसलिए एक नया reference, इसलिए झरने की तरह re-renders होते हैं भले ही theme नहीं बदला हो। ऊपर वाला useMemo इसी के लिए है। सेटअप को एक access hook से पूरा करें जो provider के बाहर स्पष्ट रूप से विफल हो।

JSX
import { useContext } from "react";

function useTheme() {
  const context = useContext(ThemeContext);
  if (context === null) {
    throw new Error(
      "useTheme must be inside <ThemeProvider>"
    );
  }
  return context;
}
एक स्पष्ट error एक चुपचाप null से बेहतर है।

एक context बनाने से पहले, पहले composition विकल्प को पूरी तरह आज़मा लें। यदि कोई मध्यवर्ती परत केवल एक prop को आगे पहुँचाने के अलावा कुछ नहीं करती, तो संरचना उलट दें: पेड़ के शीर्ष पर, जहाँ डेटा रहता है, element बनाएं, और उसे children या एक समर्पित prop के ज़रिए नीचे पास करें। मध्यवर्ती परत generic बन जाती है और डेटा अब किसी ऐसे कंपोनेंट से नहीं गुज़रता जो उसका उपयोग नहीं करता।

JSX
function App({ currentUser }) {
  return (
    <Layout
      header={<TopBar user={currentUser} />}
      content={<Dashboard />}
    />
  );
}
Layout को currentUser के बारे में कुछ नहीं पता: यह तैयार-बने elements को उनकी जगह पर बैठा देता है।

ज्ञान जांच

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

  1. एक context consumer React.memo में लपेटा गया है और context मान बदलता है। क्या होता है?
    • यह फिर से render नहीं होता: React.memo सभी अपडेट रोक देता है
    • यह फिर से render होता है: React.memo props की तुलना करता है, context मानों की नहीं
    • यह केवल तभी फिर से render होता है जब उसके props भी बदलें
  2. एक provider में value को पास की गई object को memoize क्यों करें?
    • हर render पर object के निर्माण को तेज़ करने के लिए
    • क्योंकि provider को एक immutable मान की आवश्यकता होती है
    • ताकि reference केवल तभी बदले जब डेटा बदले, और consumers के अनावश्यक re-renders से बचा जा सके
  3. बहुत बार अपडेट होने वाली state के लिए context की मुख्य सीमा क्या है?
    • कोई selectors नहीं: हर अपडेट सभी consumers को फिर से render करता है, यहाँ तक कि वे भी जो मान का केवल एक हिस्सा उपयोग करते हैं
    • Context असिंक्रोनस है और अपडेट में देरी करता है
    • Context केवल primitive मान संग्रहीत कर सकता है