उथले प्रतिक्रिया में काम की तुलना कैसे करता है


96

में इस दस्तावेज़ प्रतिक्रिया की है, यह कहा जाता है कि

shallowCompare वर्तमान प्रॉप्स और नेक्स्टप्रॉप्स ऑब्जेक्ट्स के साथ-साथ वर्तमान स्थिति और नेक्स्टस्टेट ऑब्जेक्ट्स पर एक उथले समानता की जांच करता है।

जिस चीज को मैं समझ नहीं पा रहा हूं वह यह है कि यदि यह उथली वस्तुओं की तुलना करता है तो shouldComponentUpdate विधि हमेशा सही रहेगी, जैसे कि

हमें राज्यों को नहीं बदलना चाहिए।

और यदि हम राज्यों को म्यूट नहीं कर रहे हैं, तो तुलना हमेशा झूठी होगी और इसलिए अद्यतन अद्यतन हमेशा सही रहेगा। मैं उलझन में हूं कि यह कैसे काम कर रहा है और प्रदर्शन को बढ़ावा देने के लिए हम इसे कैसे ओवरराइड करेंगे।

जवाबों:


131

उथले तुलना समानता के लिए जाँच करता है। स्केलर मानों (संख्याओं, तारों) की तुलना करते समय यह उनके मूल्यों की तुलना करता है। वस्तुओं की तुलना करते समय, यह उनके गुणों की तुलना नहीं करता है - केवल उनके संदर्भों की तुलना की जाती है (जैसे "वे एक ही वस्तु को इंगित करते हैं)"।

आइए userवस्तु के निम्नलिखित आकार पर विचार करें

user = {
  name: "John",
  surname: "Doe"
}

उदाहरण 1:

const user = this.state.user;
user.name = "Jane";

console.log(user === this.state.user); // true

ध्यान दें कि आपने उपयोगकर्ताओं का नाम बदल दिया है। इस परिवर्तन के साथ भी वस्तुएँ समान हैं। वे संदर्भ बिल्कुल एक जैसे हैं।

उदाहरण 2:

const user = clone(this.state.user);
console.log(user === this.state.user); // false

अब, गुण गुणों में किसी भी बदलाव के बिना वे पूरी तरह से अलग हैं। मूल ऑब्जेक्ट को क्लोन करके आप नई कॉपी बनाते हैं, अलग-अलग संदर्भों के साथ।

क्लोन फ़ंक्शन इस रूप में दिखाई दे सकता है (ES6 सिंटैक्स)

const clone = obj => Object.assign({}, ...obj);

परिवर्तनों का पता लगाने के लिए उथला तुलना कुशल तरीका है। यह उम्मीद है कि आप डेटा को म्यूट नहीं करते हैं।


इसलिए यदि हम कोड लिख रहे हैं तो यदि हमारे पास स्केलर मान हैं तो क्या हमें उन्हें म्यूट करना चाहिए क्योंकि यदि हम उन्हें क्लोन करेंगे, तो समानता की जांच झूठी हो जाएगी?
अजय गौड़

29
@ अजयगौर हालांकि यह उत्तर आपको जावास्क्रिप्ट में सख्त समानता (===) को समझने में मदद कर सकता है, लेकिन यह आपको रिएक्ट में shallowCompare () फ़ंक्शन के बारे में कुछ नहीं बताता है (मुझे लगता है कि उत्तर देने वाले ने आपके प्रश्न को गलत समझा)। वास्तव में आपके द्वारा प्रदत्त डॉक में उथला काम () क्या है: वस्तुओं की कुंजियों की तुलना करना और उनकी वापसी करना तब सही होता है जब प्रत्येक वस्तु में एक कुंजी के मान कड़ाई से बराबर नहीं होते हैं। यदि आप अभी भी इस फ़ंक्शन को नहीं समझते हैं और आपको राज्य को म्यूट क्यों नहीं करना चाहिए, तो मैं आपके लिए एक उत्तर लिख सकता हूं।
12

7
यह सच नहीं है। यह देखो। github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/…
ब्राइट ली

5
यह उत्तर जेएस में समानता (==) और सख्त समानता (===) ऑपरेटरों के बीच अंतर का वर्णन कर रहा है। सवाल उथले तुलना के बारे में है, जो रिएक्ट में दो वस्तुओं के सभी सहारा के बीच समानता की जांच करके लागू किया जाता है।
मेटो ह्रस्टनिक

क्या आप उस पर जवाब लिख सकते हैं?
अजय गौर 12

35

उथले तुलना तब होती है जब तुलना की जाने वाली वस्तुओं के गुणों को "===" या सख्त समानता का उपयोग करके किया जाता है और गुणों में गहराई से तुलना नहीं करेगा। उदाहरण के लिए

// a simple implementation of the shallowCompare.
// only compares the first level properties and hence shallow.
// state updates(theoretically) if this function returns true.
function shallowCompare(newObj, prevObj){
    for (key in newObj){
        if(newObj[key] !== prevObj[key]) return true;
    }
    return false;
}
// 
var game_item = {
    game: "football",
    first_world_cup: "1930",
    teams: {
         North_America: 1,
         South_America: 4,
         Europe: 8 
    }
}
// Case 1:
// if this be the object passed to setState
var updated_game_item1 = {
    game: "football",
    first_world_cup: "1930",
    teams: {
         North_America: 1,
         South_America: 4,
         Europe: 8 
    }
}
shallowCompare(updated_game_item1, game_item); // true - meaning the state
                                               // will update.

यद्यपि दोनों वस्तुएं समान दिखाई देती हैं, game_item.teamsलेकिन यह एक ही संदर्भ नहीं है updated_game_item.teams। 2 वस्तुओं के समान होने के लिए, उन्हें एक ही वस्तु की ओर इशारा करना चाहिए। इस प्रकार राज्य में इस परिणाम का मूल्यांकन किया जाना है

// Case 2:
// if this be the object passed to setState
var updated_game_item2 = {
    game: "football",
    first_world_cup: "1930",
    teams: game_item.teams
}
shallowCompare(updated_game_item2, game_item); // false - meaning the state
                                               // will not update.

इस बार हर एक संपत्तियों की सख्त तुलना सही है क्योंकि नए और पुराने ऑब्जेक्ट में टीम की संपत्ति एक ही वस्तु की ओर इशारा करती है।

// Case 3:
// if this be the object passed to setState
var updated_game_item3 = {
    first_world_cup: 1930
}
shallowCompare(updated_game_item3, game_item); // true - will update

updated_game_item3.first_world_cupसंपत्ति में विफल रहता है 1930 के रूप में सख्त मूल्यांकन एक संख्या है, जबकि game_item.first_world_cupएक श्रृंखला है। अगर तुलना ढीली होती (==) तो यह बीत चुका होता। बहरहाल, यह भी राज्य अद्यतन में परिणाम होगा।

अतिरिक्त नोट्स:

  1. गहरी तुलना करना व्यर्थ है क्योंकि यह प्रदर्शन को काफी प्रभावित करेगा यदि राज्य वस्तु का गहरा घोंसला है। लेकिन अगर इसका बहुत नेस्टेड नहीं है और आपको अभी भी एक गहरी तुलना की आवश्यकता है, तो इसे shouldComponentUpdate में लागू करें और देखें कि क्या ठीक है।
  2. आप निश्चित रूप से सीधे स्टेट ऑब्जेक्ट को म्यूट कर सकते हैं लेकिन घटकों की स्थिति प्रभावित नहीं होगी, क्योंकि इसके सेटस्टैट विधि प्रवाह में जो घटक अद्यतन चक्र हुक को लागू करता है। यदि आप घटक जीवन-चक्र हुक से जानबूझकर बचने के लिए राज्य वस्तु को सीधे अपडेट करते हैं, तो संभवतः आपको डेटा को संग्रहीत करने के लिए एक साधारण चर या वस्तु का उपयोग करना चाहिए न कि राज्य वस्तु का।

क्या इसका मतलब यह नहीं है कि अगर मैं किसी वस्तु को सहारा देता हूं या राज्य की तुलना अगले राज्य से करता हूं, तो घटक कभी भी फिर से प्रस्तुत नहीं होगा क्योंकि अगर उस वस्तु के गुण बदल गए हैं, तो भी यह उसी वस्तु की ओर इशारा करेगा, इस प्रकार, जिसके परिणामस्वरूप असत्य, इस प्रकार, पुन: प्रतिपादन नहीं?
जावास्क्रिप्ट

@javascripting - यही वजह है कि आप क्लोन करेंगे (उदाहरण के लिए Object.assign () का उपयोग करके) जब वे बदलते हैं तो उन्हें बदलने के बजाय रिएक्ट तब होगा जब संदर्भ परिवर्तन और घटक को अपडेट करने की आवश्यकता होगी।
Mac_W

यदि prevObjकोई कुंजी है जो newObjनहीं है, तो तुलना विफल हो जाएगी।
मेज़ेलर

@mzedeler - क्योंकि newObj पर iterates में "for" नहीं है और prevObj पर नहीं है। ब्राउज़र डेवलपर कंसोल में कोड को चलाने का प्रयास करें। इसके अलावा कृपया उथले के इस कार्यान्वयन को बहुत गंभीरता से न लें, यह केवल अवधारणा को प्रदर्शित करने के लिए है
supi

सरणियों के बारे में क्या?
जुआन डे ला क्रूज़

27

उथले की जाँच करता है कि क्या स्ट्रिंग, संख्याओं जैसे आदिम प्रकारों के मामले में दो मान समान हैं और वस्तु के मामले में यह सिर्फ संदर्भ की जाँच करता है । इसलिए यदि आप एक गहरी नेस्टेड ऑब्जेक्ट की तुलना करते हैं, तो यह केवल उस ऑब्जेक्ट के अंदर के मूल्यों को नहीं संदर्भ की जांच करेगा।


11

प्रतिक्रिया में उथले तुलना की विरासत व्याख्या भी है :

shallowCompare वर्तमान प्रॉप्स और नेक्स्टप्रॉप्स ऑब्जेक्ट्स के साथ-साथ वर्तमान स्थिति और नेक्स्टस्टेट ऑब्जेक्ट्स पर एक उथले समानता की जांच करता है।

यह वस्तुओं की कुंजी की तुलना करने और प्रत्येक वस्तु में एक कुंजी के मान कड़ाई से बराबर नहीं होने पर वापस लौटने पर ऐसा करता है।

UPD : वर्तमान प्रलेखन में उथले तुलना के बारे में कहा गया है:

यदि आपके रिएक्ट कंपोनेंट के रेंडर () फंक्शन उसी प्रॉप्स और स्टेट को दिए गए परिणाम को रेंडर करते हैं, तो आप कुछ मामलों में परफॉर्मेंस बूस्ट के लिए React.PureComponent का उपयोग कर सकते हैं।

React.PureComponent's shouldComponentUpdate () केवल उथली वस्तुओं की तुलना करती है। यदि इनमें जटिल डेटा संरचनाएँ हैं, तो यह गहरे मतभेदों के लिए गलत-नकारात्मक उत्पादन कर सकती है। जब आप सरल प्रॉप्स और स्थिति की अपेक्षा करते हैं, तो केवल PureComponent का विस्तार करें, या जब आप जानते हैं कि गहरी डेटा संरचनाएं बदल गई हैं, तो बल का उपयोग करें ()

UPD2: मुझे लगता है कि उथले तुलना समझ के लिए सुलह भी महत्वपूर्ण विषय है।


यह "असत्य" नहीं होना चाहिएand returning true when the values
rahulg

2

@Supi से ऊपर उथला समान स्निपेट ( https://stackoverflow.com/a/51343585/800608 ) prevObjएक कुंजी है जो अगर नहीं है तो विफल रहता newObjहै। यहाँ एक कार्यान्वयन है जो इसे ध्यान में रखना चाहिए:

const shallowEqual = (objA, objB) => {
  if (!objA || !objB) {
    return objA === objB
  }
  return !Boolean(
    Object
      .keys(Object.assign({}, objA, objB))
      .find((key) => objA[key] !== objB[key])
  )
}

ध्यान दें कि उपरोक्त पॉलीफ़िल के बिना एक्सप्लोरर में काम नहीं करता है।


अच्छा लग रहा है लेकिन इस मामले में दो NaN के रिटर्न को गलत मानते हुए, जबकि पिछले उत्तर में यह सच है।
स्पेडर शट

0

उदाहरणों के साथ एक कार्यान्वयन है।

const isObject = value => typeof value === 'object' && value !== null;

const compareObjects = (A, B) => {
  const keysA = Object.keys(A);
  const keysB = Object.keys(B);
 
  if (keysA.length !== keysB.length) {
    return false;
  }
 
  return !keysA.some(key => !B.hasOwnProperty(key) || A[key] !== B[key]);
};

const shallowEqual = (A, B) => {
  if (A === B) {
    return true;
  }
 
  if ([A, B].every(Number.isNaN)) {
    return true;
  }
  
  if (![A, B].every(isObject)) {
    return false;
  }
  
  return compareObjects(A, B);
};

const a = { field: 1 };
const b = { field: 2 };
const c = { field: { field: 1 } };
const d = { field: { field: 1 } };

console.log(shallowEqual(1, 1)); // true
console.log(shallowEqual(1, 2)); // false
console.log(shallowEqual(null, null)); // true
console.log(shallowEqual(NaN, NaN)); // true
console.log(shallowEqual([], [])); // true
console.log(shallowEqual([1], [2])); // false
console.log(shallowEqual({}, {})); // true
console.log(shallowEqual({}, a)); // false
console.log(shallowEqual(a, b)); // false
console.log(shallowEqual(a, c)); // false
console.log(shallowEqual(c, d)); // false

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.