नमस्ते👋🏻,
यह लेख खास तौर पर उन शुरुआती लोगों के लिए बनाया गया है जो कई घटकों के बीच स्थिति को प्रबंधित करने के लिए अधिक प्रभावी तरीके सीखने के लिए उत्सुक हैं। इसका उद्देश्य प्रॉप ड्रिलिंग के सामान्य मुद्दे को संबोधित करना भी है जो आपके कोड को बनाए रखना और समझना कठिन बना सकता है। आइए इस बात से शुरू करें कि कॉन्टेक्स्ट एपीआई किस तरह की समस्या का समाधान करता है।
यदि आप वीडियो प्रारूप पसंद करते हैं, तो यहां ट्यूटोरियल है जिसे आप मेरे YouTube चैनल पर देख सकते हैं।
क्या आप जानते हैं कि कभी-कभी आपको पैरेंट कॉम्पोनेंट से चाइल्ड कॉम्पोनेंट तक डेटा पास करने की ज़रूरत होती है, और आप बीच में कई कॉम्पोनेंट से प्रॉप्स पास करते हैं? इसे प्रॉप ड्रिलिंग कहा जाता है, और यह जल्दी ही गड़बड़ हो सकता है। आइए इसे स्पष्ट करने के लिए एक उदाहरण के ज़रिए चलते हैं।
जैसा कि आरेख में दिखाया गया है, कल्पना करें कि आपने App
घटक में कुछ डेटा प्राप्त किया है, जो आपके एप्लिकेशन के मूल में स्थित है। अब, यदि एक गहराई से नेस्टेड घटक, जैसे कि Grandchild
घटक, को इस डेटा तक पहुंचने की आवश्यकता है, तो आप आमतौर पर इसे Grandchild
तक पहुंचने से पहले Parent
और Child
घटकों के माध्यम से प्रॉप्स के रूप में पास करेंगे। जैसे-जैसे आपका ऐप बढ़ता है, यह बदसूरत हो सकता है।
यहाँ एक और दृश्य प्रतिनिधित्व है:
ऊपर दिए गए उदाहरण में, Profile
घटक को उपयोगकर्ता डेटा की आवश्यकता होती है, लेकिन इस डेटा को पहले App
और Navigation
घटकों से होकर गुजरना पड़ता है, भले ही ये मध्यवर्ती घटक स्वयं डेटा का उपयोग न करें। तो, हम इसे कैसे साफ़ करें? यहीं पर संदर्भ API काम आता है।
प्रॉप्स ड्रिलिंग:
React.js में Context API आपको कॉम्पोनेंट ट्री के प्रत्येक स्तर के माध्यम से प्रॉप्स के रूप में पास किए बिना कॉम्पोनेंट के बीच डेटा पास करने देता है। यह एक वैश्विक स्टेट मैनेजमेंट सिस्टम की तरह काम करता है जहाँ आप अपने स्टेट को कॉन्टेक्स्ट ऑब्जेक्ट में परिभाषित करते हैं, और फिर आप कॉम्पोनेंट ट्री में कहीं भी इसे आसानी से एक्सेस कर सकते हैं। आइए इसे एक उदाहरण से समझते हैं।
जैसा कि आप आरेख में देख सकते हैं, हमारे पास एक संदर्भ ऑब्जेक्ट है जो कई घटकों द्वारा एक्सेस किए जाने वाले डेटा को संग्रहीत करता है। यह डेटा API या तृतीय-पक्ष सेवाओं से प्राप्त किया जाता है। किसी भी घटक में इस संदर्भ डेटा तक पहुँचने से पहले, हमें उन सभी घटकों को लपेटना होगा जिन्हें इस डेटा की आवश्यकता होती है एक संदर्भ प्रदाता घटक में।
अगर हमें सिर्फ़ नेविगेशन और प्रोफ़ाइल कॉम्पोनेंट में डेटा एक्सेस करने की ज़रूरत है, तो हमें ऐप कॉम्पोनेंट को रैप अप करने की ज़रूरत नहीं है। एक बार जब आप ContextProvider
के साथ संबंधित कॉम्पोनेंट को रैप कर लेते हैं, तो आप सीधे किसी भी कॉम्पोनेंट में कॉन्टेक्स्ट डेटा एक्सेस कर सकते हैं जो इसका इस्तेमाल करता है। अगर आप अभी भी इसे नहीं समझ पाए हैं, तो चिंता न करें; आइए कोड में गोता लगाएँ और इसे कार्रवाई में देखें।
सबसे पहले, आइए Vite.js का उपयोग करके एक React ऐप बनाएं। प्रोजेक्ट सेट अप करने के लिए बस निम्नलिखित कमांड को कॉपी करें।
npm create vite@latest
cd project_name // to change to project directory npm install npm run dev
फिर आप अपने ब्राउज़र में अपना डेवलपमेंट सर्वर http://localhost:5173
खोल सकते हैं।
सबसे पहले, आइए आवश्यक फ़ोल्डर्स बनाएँ। यहाँ हमारे प्रोजेक्ट की फ़ोल्डर संरचना है।
src | components | context
घटक फ़ोल्डर में आइए Profile.jsx
फ़ाइल बनाएं, और निम्नलिखित कोड जोड़ें।
import React from 'react' const Profile = () => { return ( <div>Profile</div> ) } export default Profile
घटक फ़ोल्डर में Navbar.jsx
नामक एक और घटक बनाएँ।
import Profile from './Profile' const Navbar = () => { return ( <nav style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "90%", height: "10vh", backgroundColor: theme === "light" ? "#fff" : "#1b1b1b", color: theme === "light" ? "#1b1b1b" : "#fff", border: "1px solid #fff", borderRadius: "5px", padding: "0 20px", marginTop: "40px", }}> <h1>LOGO</h1> <Profile /> </nav> ) } export default Navbar
आइए इस <Navbar />
घटक को App.jsx
फ़ाइल में आयात करें।
import Navbar from "./components/Navbar"; function App() { return ( <main style={{ display: "flex", flexDirection: "column", justifyContent: "start", alignItems: "center", height: "100vh", width: "100vw", }} > <Navbar /> </main> ); } export default App;
तो मूलतः, <Profile />
घटक <Navbar />
का संतान है और <Navbar />
घटक <App />
का संतान है।
आइए context
फ़ोल्डर में UserContext.jsx
फ़ाइल बनाएँ। फ़ाइल में निम्न कोड जोड़ें।
import { createContext, useEffect, useState } from "react"; export const UserContext = createContext(); export const UserProvider = ({ children }) => { const [user, setUser] = useState(null); const fetchUserData = async (id) => { const response = await fetch( `https://jsonplaceholder.typicode.com/users/${id}` ).then((response) => response.json()); console.log(response); setUser(response); }; useEffect(() => { fetchUserData(1); }, []); return ( <UserContext.Provider value={{ user, fetchUserData }} > {children} </UserContext.Provider> ); };
createContext
उपयोग करके एक खाली UserContext
ऑब्जेक्ट बनाते हैं। हम इसे react
से आयात करना सुनिश्चित करते हैं। हम context ऑब्जेक्ट के अंदर डिफ़ॉल्ट मान जोड़ सकते हैं, लेकिन हम इसे अभी के लिए null रखते हैं।
UserProvider
बनाते हैं, जो UserContext
उपयोग करके एक प्रदाता लौटाता है, जैसे UserContext.Provider
। यह बच्चों के घटकों के चारों ओर लपेटता है, और मूल्य में, हम कुछ भी पास कर सकते हैं जिसे हम बच्चे के घटकों में उपयोग करना चाहते हैं।
fetchUserData
फ़ंक्शन id
स्वीकार करता है और उपयोगकर्ता डेटा लाने के लिए उस आईडी का उपयोग करता है। फिर हम प्रतिक्रिया को user
स्थिति में संग्रहीत करते हैं।
useEffect
में fetchUserData
फ़ंक्शन को कॉल कर रहे हैं, इसलिए पृष्ठ लोड होने पर, यह फ़ंक्शन को कॉल करता है, और यह user
स्थिति में डेटा को इंजेक्ट करता है।
अब, आइए इस संदर्भ को <App />
घटक में उपयोग करें। <UserProvider />
का उपयोग करके <NavBar />
घटक को लपेटें; निम्न कोड के समान:
<UserProvider> <Navbar /> </UserProvider>
आइए <Profile />
घटक में user
स्थिति का उपयोग करें। इसके लिए, हम useContext
हुक का उपयोग करेंगे। यह UserContext
लेता है और UserProvider
में हमारे द्वारा पास किए गए मान जैसे कि user
स्थिति और fetchUserData
फ़ंक्शन प्रदान करता है। याद रखें, हमें <Profile />
घटक को लपेटने की आवश्यकता नहीं है क्योंकि यह पहले से ही <Navbar />
घटक में है जो पहले से ही प्रदाता के साथ लपेटा हुआ है।
Profile.jsx
खोलें, और निम्नलिखित कोड जोड़ें।
const { user } = useContext(UserContext); if (user) { return ( <span style={{ fontWeight: "bold", }} > {user.name} </span> ); } else { return <span>Login</span>; }
यहाँ, हम UserContext
से user
स्टेट का उपयोग कर रहे हैं। यदि user
है तो हम यूजरनेम प्रदर्शित करेंगे अन्यथा, हम केवल एक लॉगिन संदेश प्रदर्शित करेंगे। अब, यदि आप आउटपुट देखते हैं तो नेवबार घटक में एक यूजर नेम होना चाहिए। इस तरह हम किसी भी घटक के संदर्भ में किसी भी स्टेट का सीधे उपयोग कर सकते हैं। इस स्टेट का उपयोग करने वाले घटक को <Provider />
के भीतर लपेटा जाना चाहिए।
आप कई संदर्भों का भी उपयोग कर सकते हैं। आपको बस प्रदाता घटकों को दूसरे प्रदाता घटक के भीतर लपेटना होगा जैसा कि निम्नलिखित उदाहरण में दिखाया गया है।
<ThemeProvider> <UserProvider> <Navbar /> </UserProvider> </ThemeProvider>
उपरोक्त उदाहरण में, हम <ThemeProvider />
उपयोग कर रहे हैं जो थीम स्थिति का प्रबंधन करता है।
आप एकाधिक संदर्भ प्रदाताओं के उपयोग का पूरा उदाहरण देखने के लिए उपरोक्त यूट्यूब वीडियो देख सकते हैं।
एक समस्या तब होती है जब आप कई घटकों में संदर्भ API का उपयोग करते हैं। जब भी संदर्भ API में स्थिति या मान बदलता है, तो यह उस विशेष संदर्भ के लिए सब्सक्राइब किए गए सभी घटकों को फिर से रेंडर करता है, भले ही सभी घटक बदली हुई स्थिति का उपयोग न कर रहे हों। इस पुनः-रेंडरिंग समस्या को समझने के लिए, आइए एक <Counter />
घटक बनाएं जो गिनती मानों को संग्रहीत और प्रदर्शित करने के लिए संदर्भ का उपयोग करता है।
निम्न उदाहरण देखें। आप कॉम्पोनेंट फ़ोल्डर में Counter.jsx
फ़ाइल बना सकते हैं और निम्न कोड पेस्ट कर सकते हैं।
import { createContext, memo, useContext, useState } from "react"; const CountContext = createContext(); const CountProvider = ({ children }) => { const [count, setCount] = useState(0); return ( <CountContext.Provider value={{ count, setCount }}> {children} </CountContext.Provider> ); }; function CountTitle() { console.log("This is Count Title component"); return <h1>Counter Title</h1>; } function CountDisplay() { console.log("This is CountDisplay component"); const { count } = useContext(CountContext); return <div>Count: {count}</div>; } function CounterButton() { console.log("This is CounterButton component"); const { count, setCount } = useContext(CountContext); return ( <> <CountTitle /> <CountDisplay /> <button onClick={() => setCount(count + 1)}>Increase</button> </> ); } export default function Counter() { return ( <CountProvider> <CounterButton /> </CountProvider> ); }
उपरोक्त कोड में:
createContext.
का उपयोग करके एक CountContext
ऑब्जेक्ट बनाते हैं।
CountProvider,
हमारे पास count मानों को संग्रहीत करने के लिए एक स्टेट है। हम value prop के माध्यम से child components को count
और setCount
विधि भेज रहे हैं।
हमने घटकों को अलग-अलग बनाया है ताकि यह देखा जा सके कि अलग-अलग घटक कितनी बार पुनः प्रस्तुत होते हैं।
<CountTitle />
: यह घटक केवल शीर्षक प्रदर्शित करता है और संदर्भ से किसी भी मान का उपयोग भी नहीं करता है।
<CountDisplay />
: यह घटक गणना मान प्रदर्शित करता है और संदर्भ से count
स्थिति का उपयोग करता है।
<CounterButton />
: यह घटक उपरोक्त घटक और बटन दोनों को प्रस्तुत करता है जो setCount
उपयोग करके गिनती मान बढ़ाता है।
अंत में, हम <CounterButton />
घटक को CountProvider
घटक के भीतर लपेट रहे हैं ताकि अन्य घटक count मानों तक पहुंच सकें।
अब, यदि आप कोड चलाते हैं और Increase
बटन पर क्लिक करते हैं, तो आप लॉग में देखेंगे कि प्रत्येक घटक हर बार स्थिति बदलने पर पुनः रेंडर हो रहा है। <CountTitle />
गिनती मानों का उपयोग भी नहीं कर रहा है, फिर भी यह पुनः रेंडर हो रहा है। ऐसा इसलिए हो रहा है क्योंकि <CountTitle />
का पैरेंट घटक जो <CounterButton />
है, गिनती के मान का उपयोग और अद्यतन कर रहा है और इसीलिए पुनः रेंडर हो रहा है।
हम इस व्यवहार को कैसे अनुकूलित कर सकते हैं? इसका उत्तर है memo
। रिएक्ट memo
आपको किसी कॉम्पोनेंट को फिर से रेंडर करने से रोकता है जब उसके प्रॉप्स अपरिवर्तित होते हैं। <CountTitle />
कॉम्पोनेंट के बाद, आइए निम्न पंक्ति जोड़ें।
const MemoizedCountTitle = React.memo(CountTitle)
अब, <CounterButton />
घटक में, जहाँ हम <CountTitle />
घटक को रेंडर कर रहे हैं, <CountTitle />
को <MemoizedCountTitle />
से प्रतिस्थापित करें, जैसा कि निम्नलिखित कोड में है:
<> <MemoizedCountTitle /> <CountDisplay /> <button onClick={() => setCount(count + 1)}>Increase</button> </>
अब, यदि आप गिनती बढ़ाते हैं और लॉग की जांच करते हैं, तो आपको यह देखने में सक्षम होना चाहिए कि यह अब <CountTitle />
घटक को रेंडर नहीं कर रहा है।
Redux
जटिल स्टेट मैनेजमेंट के लिए स्टेट मैनेजमेंट लाइब्रेरी है जिसमें अधिक पूर्वानुमानित स्टेट ट्रांजिशन होते हैं। जबकि कॉन्टेक्स्ट API को सरल स्टेट मैनेजमेंट और प्रॉप ड्रिलिंग के बिना कॉम्पोनेंट ट्री के माध्यम से डेटा पास करने के लिए डिज़ाइन किया गया है। तो, कब किसे चुनना है?
एक और लाइब्रेरी भी है जो स्टेट मैनेजमेंट के लिए एक लोकप्रिय विकल्प है। रिएक्ट रिकॉइल ।
यदि आप रिएक्ट रिकॉइल के बारे में अधिक जानने में रुचि रखते हैं, तो मुझे टिप्पणियों में बताएं और मैं आपकी प्रतिक्रिया के आधार पर इस विषय पर गहन ट्यूटोरियल बनाऊंगा।
React.js
Context API कई घटकों में स्थितियों को प्रबंधित करने का एक शक्तिशाली और कुशल तरीका प्रदान करता है, जो प्रॉप ड्रिलिंग के मुद्दे को प्रभावी ढंग से संबोधित करता है। Context API का उपयोग करके, आप अपने कोड को सरल बना सकते हैं, अनावश्यक री-रेंडर को कम कर सकते हैं और समग्र एप्लिकेशन प्रदर्शन में सुधार कर सकते हैं।
जबकि संदर्भ एपीआई सरल राज्य प्रबंधन के लिए आदर्श है, अधिक जटिल अनुप्रयोगों को Redux
या React Recoil
जैसी अन्य राज्य प्रबंधन लाइब्रेरी का उपयोग करने से लाभ हो सकता है। इन उपकरणों का उपयोग कब और कैसे करना है, यह समझने से आप अधिक रखरखाव योग्य और स्केलेबल React एप्लिकेशन बनाने में सक्षम होंगे।
इस लेख को पढ़ने के लिए धन्यवाद, मुझे आशा है कि आपको यह उपयोगी लगा होगा। यदि आप React, Redux और Next.js का उपयोग करके प्रोजेक्ट बनाना और सीखना चाहते हैं, तो आप यहाँ मेरे YouTube चैनल पर जा सकते हैं: CodeBucks
यहां मेरे अन्य लेख हैं जिन्हें आप पढ़ना पसंद करेंगे:
Lenis और GSAP के साथ Next.js में सुचारू स्क्रॉलिंग कैसे लागू करें
शीर्ष 10 लोकप्रिय VS कोड थीम जिन्हें आपको अवश्य आज़माना चाहिए
मेरे व्यक्तिगत ब्लॉग पर जाएँ: DevDreaming