React Hook useEffect has a missing dependency: 'x'. Either include it or remove the dependency array.अधिकांश डेवलपर्स इसे एस्लिंट-अक्षम टिप्पणी के साथ चुप करा देते हैं। यह तब तक काम करता है जब तक कि यह पुराने डेटा बग का कारण न बन जाए जिसे ढूंढने में एक दिन लग जाता है। चेतावनी आम तौर पर सही होती है, और प्रत्येक स्थिति के लिए एक सही समाधान होता है।
📋 Table of Contents
- चेतावनी क्यों मौजूद है
- समाधान 1: बस निर्भरता जोड़ें
- समाधान 2: इसे जोड़ने के बाद प्रभाव लूप हो जाता है
- फिक्स 3: फ़ंक्शन निर्भरताएँ – कॉलबैक का उपयोग करें
- में लपेटें समाधान 4: आपको दोबारा चलाए बिना नवीनतम मूल्य की आवश्यकता है
- समाधान 5: राज्य को उसके पिछले मान से अद्यतन करना
- जब नियम को अक्षम करना वास्तव में सही है
- क्या आपको भी किसी प्रभाव की आवश्यकता है?
- निर्णय मार्गदर्शिका
- अक्सर पूछे जाने वाले प्रश्न
- निष्कर्ष
चेतावनी क्यों मौजूद है
निर्भरता सरणी रिएक्ट को बताती है कि किसी प्रभाव को दोबारा कब चलाना है। यदि प्रभाव किसी ऐसे मान को पढ़ता है जो सूचीबद्ध नहीं है, तो प्रभाव उस रेंडर के मान को बनाए रखता है जिसमें वह अंतिम बार चला था – एक पुराना समापन। कोड सही दिखता है और गलत व्यवहार करता है।
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(setUser);
}, []); // ⚠️ missing dependency: 'userId'
return <div>{user?.name}</div>;
}
एक खाली सरणी के साथ फ़ेच एक बार चलता है। उपयोगकर्ता 1 से उपयोगकर्ता 2 पर नेविगेट करें और घटक उपयोगकर्ता 1 को हमेशा दिखाता रहता है। चेतावनी में बिल्कुल यही भविष्यवाणी की गई थी।
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(setUser);
}, [userId]); // ✅ refetches whenever userId changes
समाधान 1: बस निर्भरता जोड़ें
अधिकांश मामलों में चेतावनी सही है और निर्भरता जोड़ना ही संपूर्ण समाधान है। इसे पहले करें और केवल तभी आगे की जांच करें यदि यह लूप का कारण बनता है।
समाधान 2: इसे जोड़ने के बाद प्रभाव लूप हो जाता है
निर्भरता सरणी में किसी ऑब्जेक्ट, सरणी या फ़ंक्शन को जोड़ने से अक्सर एक अनंत लूप का कारण बनता है, क्योंकि उन्हें हर रेंडर पर फिर से बनाया जाता है और संदर्भ द्वारा तुलना की जाती है।
function Search({ filters }) {
const [results, setResults] = useState([]);
useEffect(() => {
search(filters).then(setResults);
}, [filters]); // new object identity every render -> infinite loop
}
वस्तु के बजाय आदिम मूल्यों पर निर्भर रहें।
useEffect(() => {
search({ query, category }).then(setResults);
}, [query, category]); // strings compare by value — stable
जब वस्तु वास्तव में माता-पिता से आती है, तो उसे वहीं याद रखें।
// Parent
const filters = useMemo(
() => ({ query, category }),
[query, category]
);
return <Search filters={filters} />;
फिक्स 3: फ़ंक्शन निर्भरताएँ – कॉलबैक का उपयोग करें
घटक निकाय में घोषित एक फ़ंक्शन प्रत्येक रेंडर पर एक नया मान होता है, इसलिए इसे सूचीबद्ध करने से प्रभाव अंतहीन रूप से फिर से चलता है।
function Dashboard({ userId }) {
// Recreated every render.
const loadData = async () => {
const res = await fetch(`/api/data/${userId}`);
return res.json();
};
useEffect(() => {
loadData().then(setData);
}, [loadData]); // loops
}
दो सही सुधार. यदि फ़ंक्शन का उपयोग केवल प्रभाव द्वारा किया जाता है, तो इसे अंदर ले जाएं – सबसे साफ विकल्प, क्योंकि निर्भरता पूरी तरह से गायब हो जाती है।
useEffect(() => {
async function loadData() {
const res = await fetch(`/api/data/${userId}`);
setData(await res.json());
}
loadData();
}, [userId]); // ✅ only the primitive is a dependency
यदि फ़ंक्शन को घटक के अन्य भागों के साथ साझा किया जाता है, तो इसेuseCallback.
const loadData = useCallback(async () => {
const res = await fetch(`/api/data/${userId}`);
return res.json();
}, [userId]);
useEffect(() => {
loadData().then(setData);
}, [loadData]); // ✅ identity only changes when userId changes
में लपेटें समाधान 4: आपको दोबारा चलाए बिना नवीनतम मूल्य की आवश्यकता है
कभी-कभी किसी प्रभाव को वैध रूप से एक बार चलना चाहिए, लेकिन अंदर कॉलबैक के लिए वर्तमान मूल्यों की आवश्यकता होती है। एक रेफरी एक परिवर्तनशील मान रखता है जो निर्भरता में भाग नहीं लेता है।
function Chat({ onMessage }) {
const onMessageRef = useRef(onMessage);
// Keep the ref current on every render.
useEffect(() => {
onMessageRef.current = onMessage;
});
useEffect(() => {
const socket = new WebSocket('wss://example.com');
socket.onmessage = (e) => onMessageRef.current(e.data);
return () => socket.close();
}, []); // ✅ connects once, always calls the latest handler
}
यह सब्सक्रिप्शन, टाइमर और ईवेंट श्रोताओं के लिए सही पैटर्न है जहां हर प्रोप परिवर्तन पर पुनः कनेक्ट करना गलत होगा।
समाधान 5: राज्य को उसके पिछले मान से अद्यतन करना
अगले राज्य की गणना करने के लिए राज्य को पढ़ना उस राज्य को एक निर्भरता बनाता है, जो आमतौर पर एक लूप का कारण बनता है। अपडेटर फॉर्म निर्भरता को हटा देता है।
// Loops: count changes -> effect re-runs -> count changes...
useEffect(() => {
const id = setInterval(() => setCount(count + 1), 1000);
return () => clearInterval(id);
}, [count]);
// ✅ No dependency on count at all.
useEffect(() => {
const id = setInterval(() => setCount(c => c + 1), 1000);
return () => clearInterval(id);
}, []);
जब नियम को अक्षम करना वास्तव में सही है
एक वैध मामला है: एक सच्चा माउंट-ओनली प्रभाव जहां आप जानबूझकर प्रारंभिक मूल्य चाहते हैं और कुछ नहीं। पहले रेंडर पर एनालिटिक्स मानक उदाहरण है।
useEffect(() => {
analytics.track('page_view', { page: pageName });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // Intentional: fire once with the initial pageName.
यदि आप नियम को अक्षम करते हैं, तो यह बताते हुए एक टिप्पणी लिखें कि चूक जानबूझकर क्यों की गई है। एक नग्न अक्षम टिप्पणी उस व्यक्ति से अप्रभेद्य है जो चेतावनी को नहीं समझता है, जिसमें छह महीने में आपका भी शामिल है।
क्या आपको भी किसी प्रभाव की आवश्यकता है?
संपूर्ण-डिप्स चेतावनियों का एक बड़ा हिस्सा उन प्रभावों से आता है जो अस्तित्व में नहीं होने चाहिए। दो सामान्य मामले:
व्युत्पन्न अवस्था. प्रॉप्स या स्थिति से किसी मान की गणना करने के लिए किसी प्रभाव की आवश्यकता नहीं होती है।
// Unnecessary effect, extra render, and a dependency warning.
const [fullName, setFullName] = useState('');
useEffect(() => { setFullName(`${first} ${last}`); }, [first, last]);
// ✅ Just calculate it during render.
const fullName = `${first} ${last}`;
किसी घटना पर प्रतिक्रिया देना। इवेंट हैंडलर में मौजूद तर्क अक्सर हैंडलर द्वारा निर्धारित प्रभाव देखने की स्थिति में समाप्त होता है।
// ✅ Do the work where the event happens.
function handleSubmit() {
submitForm(data);
analytics.track('form_submitted');
}
प्रभाव रिएक्ट के बाहर के सिस्टम के साथ सिंक्रनाइज़ करने के लिए हैं – नेटवर्क, सदस्यता, DOM, टाइमर। यदि कुछ भी बाहरी शामिल नहीं है, तो प्रभाव संभवतः गलत उपकरण है।
निर्णय मार्गदर्शिका
| स्थिति | ठीक करें |
|---|---|
| चेतावनी एक आदिम नाम देती है | इसे सरणी में जोड़ें |
| ऑब्जेक्ट या ऐरे एक लूप का कारण बनता है | इसके आदिम क्षेत्रों पर निर्भर करें, याuseMemo स्रोत पर |
| फ़ंक्शन एक लूप का कारण बनता है | इसे प्रभाव के अंदर ले जाएँ, याuseCallback |
| नवीनतम मान की आवश्यकता है, दोबारा नहीं चलना चाहिए | इसे रेफरी में संग्रहित करें |
| राज्य पिछले राज्य से निकला है | अपडेटर फ़ंक्शन फॉर्म का उपयोग करें |
| मान की गणना प्रॉप्स या स्थिति | से की जाती है रेंडर के दौरान प्रभाव हटाएं और गणना करें |
| वास्तव में केवल-माउंट | लिखित औचित्य के साथ नियम को अक्षम करें |
अक्सर पूछे जाने वाले प्रश्न
प्रश्न: मेरा प्रभाव विकास में दो बार क्यों चलता है?
ए: स्ट्रिक्ट मोड जानबूझकर लापता सफाई कार्यों को सतह पर लाने के लिए घटकों को माउंट, अनमाउंट और रीमाउंट करता है। उत्पादन में ऐसा नहीं होता. यदि डबल-रनिंग से कुछ टूट जाता है, तो आपके प्रभाव में सफ़ाई का अभाव है।
प्रश्न: क्या मैं एग्ज़ॉस्टिव-डिप्स नियम को बंद कर सकता हूँ?
उ: आप कर सकते हैं, और आप पुराने-क्लोजर बग भेजेंगे जिनका पता लगाना बेहद कठिन है। नियम वास्तविक दोषों को पकड़ता है; इसे चालू रखें और कारणों को ठीक करें।
प्रश्न: क्या हर जगह यूज़कॉलबैक से प्रदर्शन पर असर पड़ता है?
उत्तर: थोड़ा-सा – इसमें स्मृति और तुलना कार्य का खर्च आता है। इसका उपयोग वहां करें जहां पहचान स्थिरता वास्तव में मायने रखती है, जैसे निर्भरता सारणी और याद किए गए बच्चे, प्रत्येक फ़ंक्शन पर रिफ्लेक्सिव रूप से नहीं।
प्रश्न: रिएक्ट कंपाइलर के बारे में क्या?
उ: यह अधिकांश संस्मरणों को स्वचालित करता हैuseCallback औरuseMemo हाथ से करें, जिससे इन चेतावनियों की एक श्रेणी हट जाती है। यह समझने की आवश्यकता को समाप्त नहीं करता है कि आपका प्रभाव वास्तव में किन मूल्यों पर निर्भर करता है।
प्रश्न: मेरे प्रभाव को एक मूल्य की आवश्यकता है लेकिन जब यह बदलता है तो इसे दोबारा नहीं चलाया जाना चाहिए। क्या रेफरी एक हैक है?
उत्तर: नहीं, यह उस स्थिति के लिए प्रलेखित पैटर्न है। रेफरी को एक अलग प्रभाव में अद्यतन रखना और पढ़ना.current लंबे समय तक रहने वाला प्रभाव मुहावरेदार है।
निष्कर्ष
एग्ज़ॉस्टिव-डिप्स चेतावनी एक बग डिटेक्टर है, उपद्रव नहीं। पहले निर्भरता जोड़ें; यदि वह लूप करता है, तो आदिम के साथ पहचान की समस्या को ठीक करें,useMemo, याuseCallback; जब आपको पुनः चालू किए बिना वर्तमान मानों की आवश्यकता हो तो रेफरी का उपयोग करें; स्व-संदर्भित लूप को तोड़ने के लिए राज्य अपडेटर फॉर्म का उपयोग करें; और जब मान केवल प्राप्त हो तो प्रभाव को पूरी तरह से हटा दें। वास्तविक माउंट-ओनली प्रभावों के लिए एस्लिंट-अक्षम को आरक्षित करें, और हमेशा यह कहते हुए एक टिप्पणी छोड़ें कि क्यों।
🔗 Share this article
✍️ Leave a Comment