रिएक्ट फंक्शनल स्टेटलेस कंपोनेंट, प्योरकंपोनेंट, कंपोनेंट; क्या अंतर हैं और हमें कब और क्या उपयोग करना चाहिए?


188

यह जानने के लिए कि रिएक्ट v15.3.0 से , हमारे पास PureRenderMixin बिल्ट-इन के साथ विस्तार करने के लिए PureComponent नामक एक नया बेस क्लास है। जो मैं समझता हूं, वह यह है कि हुड के तहत, यह अंदर के उथले तुलना की तुलना करता है ।shouldComponentUpdate

अब हमारे पास रिएक्ट घटक को परिभाषित करने के 3 तरीके हैं:

  1. कार्यात्मक सांख्यिकीय घटक जो किसी भी वर्ग का विस्तार नहीं करता है
  2. एक घटक जो PureComponentकक्षा का विस्तार करता है
  3. एक सामान्य घटक जो Componentकक्षा का विस्तार करता है

कुछ समय पहले हम स्टेटलेस कंपोनेंट्स को प्योर कंपोनेंट्स या डंब कंपोनेंट्स भी कहते थे। लगता है "शुद्ध" शब्द की पूरी परिभाषा अब रिएक्ट में बदल गई है।

हालांकि मैं इन तीनों के बीच बुनियादी अंतरों को समझता हूं, फिर भी मुझे यकीन नहीं है कि कब क्या चुनना है । इसके अलावा प्रदर्शन प्रभाव और प्रत्येक के व्यापार-नापसंद क्या हैं?


अपडेट :

ये वो सवाल हैं जिनसे मैं स्पष्ट होने की उम्मीद करता हूं:

  • क्या मुझे अपने सरल घटकों को कार्यात्मक (सादगी के लिए) के रूप में परिभाषित करना चाहिए या PureComponentवर्ग (प्रदर्शन के लिए) का विस्तार करना चाहिए ?
  • क्या प्रदर्शन को बढ़ावा देने से मुझे खोई गई सादगी के लिए एक वास्तविक व्यापार बंद हो जाता है?
  • क्या मुझे कभी सामान्य Componentवर्ग का विस्तार करने की आवश्यकता होगी जब मैं हमेशा PureComponentबेहतर प्रदर्शन के लिए उपयोग कर सकता हूं ?

जवाबों:


315

आप कैसे तय करते हैं, आप हमारे घटकों के उद्देश्य / आकार / सहारा / व्यवहार के आधार पर इन तीनों के बीच कैसे चयन करते हैं?

कस्टम विधि के साथ React.PureComponentया उससे विस्तार प्रदर्शन के निहितार्थ हैं। स्टेटलेस फंक्शनल कंपोनेंट्स का इस्तेमाल करना एक "आर्किटेक्चरल" विकल्प है और इसका कोई भी प्रदर्शन लाभ नहीं है।React.ComponentshouldComponentUpdate

  • सरल, प्रेजेंटेशनल-केवल घटकों के लिए जिन्हें आसानी से पुन: उपयोग करने की आवश्यकता होती है, स्टेटलेस कार्यात्मक घटकों को प्राथमिकता देते हैं। इस तरह से आपको यकीन है कि उन्हें वास्तविक ऐप लॉजिक से अलग कर दिया जाता है, ताकि वे परीक्षण करने में आसान हों और उन पर अप्रत्याशित दुष्प्रभाव न पड़े। अपवाद अगर किसी कारण से आपके पास बहुत सारे हैं या यदि आपको वास्तव में उनकी रेंडर विधि को अनुकूलित करने की आवश्यकता है (जैसा कि आप shouldComponentUpdateएक स्टेटलेस फंक्शनल कंपोनेंट के लिए परिभाषित नहीं कर सकते हैं)।

  • बढ़ाएँ PureComponentयदि आप जानते हैं आपके उत्पादन सरल रंगमंच की सामग्री पर निर्भर करता है / राज्य ( "सरल" कोई नेस्टेड डेटा संरचनाओं तुलना अर्थ, PureComponent प्रदर्शन के रूप में एक उथले) और आप की जरूरत / कुछ प्रदर्शन में सुधार कर सकते हैं।

  • यदि आप अगले / वर्तमान सहारा और राज्य के बीच कस्टम तुलना तर्क प्रदर्शन करके कुछ प्रदर्शन लाभ की आवश्यकता है, तो Componentअपना खुद का विस्तार और कार्यान्वित करें shouldComponentUpdate। उदाहरण के लिए, आप जल्दी से लॉश # isEqual का उपयोग करके एक गहरी तुलना कर सकते हैं:

    class MyComponent extends Component {
        shouldComponentUpdate (nextProps, nextState) {
            return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
        }
    }

इसके अलावा, अपने स्वयं के shouldComponentUpdateया से लागू करने के PureComponentअनुकूलन कर रहे हैं, और हमेशा की तरह आप उस पर गौर करना शुरू कर देना चाहिए यदि आपके पास प्रदर्शन के मुद्दे हैं ( समय से पहले अनुकूलन से बचें )। अंगूठे के एक नियम के रूप में, मैं हमेशा इन आशाओं को काम करने की स्थिति में करने की कोशिश करता हूं, जो कि पहले से ही लागू की गई अधिकांश विशेषताओं के साथ है। जब वे वास्तव में रास्ते में मिलते हैं तो प्रदर्शन समस्याओं पर ध्यान देना बहुत आसान होता है।

अधिक जानकारी

कार्यात्मक स्टेटलेस घटक:

इन्हें केवल एक फ़ंक्शन का उपयोग करके परिभाषित किया गया है। चूंकि एक स्टेटलेस घटक के लिए कोई आंतरिक स्थिति नहीं है, इसलिए आउटपुट (जो प्रदान किया गया है) केवल इस फ़ंक्शन के इनपुट के रूप में दिए गए प्रॉपर पर निर्भर करता है।

पेशेवरों:

  • प्रतिक्रिया में एक घटक को परिभाषित करने का सबसे सरल संभव तरीका। यदि आपको किसी राज्य का प्रबंधन करने की आवश्यकता नहीं है, तो कक्षाओं और विरासत के साथ परेशान क्यों हों? एक फ़ंक्शन और वर्ग के बीच मुख्य अंतर यह है कि फ़ंक्शन के साथ आप सुनिश्चित हैं कि आउटपुट केवल इनपुट पर निर्भर करता है (पिछले निष्पादन के किसी भी इतिहास पर नहीं)।

  • आदर्श रूप से आपके ऐप में आपको अधिक से अधिक स्टेटलेस घटक रखने का लक्ष्य होना चाहिए, क्योंकि सामान्य रूप से इसका मतलब है कि आपने अपने तर्क को व्यू लेयर से बाहर ले जाकर रेडक्स जैसी किसी चीज़ में स्थानांतरित कर दिया है, जिसका अर्थ है कि आप अपने असली तर्क का परीक्षण कर सकते हैं बिना कुछ भी प्रस्तुत किए। (परीक्षण के लिए बहुत आसान, अधिक पुन: प्रयोज्य, आदि)।

विपक्ष:

  • कोई जीवन पद्धति नहीं। आपके पास परिभाषित करने componentDidMountऔर अन्य मित्रों के लिए कोई रास्ता नहीं है । आम तौर पर आप ऐसा करते हैं कि पदानुक्रम में उच्चतर मूल घटक के भीतर आप सभी बच्चों को स्टेटलेस में बदल सकते हैं।

  • जब आप परिभाषित नहीं कर सकते, तब से मैन्युअल रूप से नियंत्रण का कोई तरीका नहीं है, जब एक पुन: रेंडर करने की आवश्यकता होती है shouldComponentUpdate। हर बार घटक नए प्रॉप्स (उथले तुलना, आदि के लिए कोई रास्ता नहीं) प्राप्त करता है। भविष्य में, प्रतिक्रिया स्वचालित रूप से स्टेटलेस घटकों को अनुकूलित कर सकती है, अब आपके लिए कुछ पुस्तकालयों का उपयोग किया जा सकता है। चूंकि स्टेटलेस घटक केवल कार्य हैं, मूल रूप से यह "फ़ंक्शन मेमोइज़ेशन" की क्लासिक समस्या है।

  • Refs समर्थित नहीं हैं: https://github.com/facebook/react/issues/4936

एक घटक जो PureComponent class VS को बढ़ाता है एक सामान्य घटक जो घटक वर्ग का विस्तार करता है:

PureRenderMixinआप एक React.createClassवाक्यविन्यास का उपयोग कर परिभाषित वर्ग के लिए संलग्न कर सकते थे करने के लिए इस्तेमाल किया प्रतिक्रिया । मिक्सचर बस shouldComponentUpdateअगले प्रदर्शन और अगले राज्य के बीच एक उथले तुलना को परिभाषित करेगा कि क्या कुछ भी बदल गया है। यदि कुछ नहीं बदलता है, तो फिर से रेंडर करने की आवश्यकता नहीं है।

यदि आप ES6 सिंटैक्स का उपयोग करना चाहते हैं, तो आप मिश्रण का उपयोग नहीं कर सकते। इसलिए सुविधा के लिए रिएक्ट ने एक ऐसा PureComponentवर्ग पेश किया जिसे आप उपयोग करने के बजाय विरासत में प्राप्त कर सकते हैं Component। उसी तरह से PureComponentलागू shouldComponentUpdateकरता है PureRendererMixin। यह ज्यादातर सुविधा की बात है, इसलिए आपको इसे स्वयं लागू करने की आवश्यकता नहीं है, क्योंकि वर्तमान / अगली स्थिति और प्रॉप्स के बीच उथले तुलना संभवतः सबसे आम परिदृश्य है जो आपको कुछ त्वरित प्रदर्शन जीत दिला सकता है।

उदाहरण:

class UserAvatar extends Component {
    render() {
       return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
    }
} 

जैसा कि आप देख सकते हैं आउटपुट निर्भर करता है props.imageUrlऔर props.username। यदि किसी मूल घटक में आप <UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />समान प्रॉप्स के साथ रेंडर करते हैं, तो रिएक्ट renderहर बार कॉल करेगा , भले ही आउटपुट बिल्कुल समान हो। हालांकि याद रखें कि रिएक्ट इम्प्रूवमेंट डोम में भिन्नता है, इसलिए DOM वास्तव में अपडेट नहीं किया जाएगा। फिर भी, डोम का प्रदर्शन करना महंगा हो सकता है, इसलिए इस परिदृश्य में यह एक बेकार होगा।

यदि UserAvatarघटक PureComponentइसके बजाय विस्तारित होता है , तो एक उथले तुलना की जाती है। और क्योंकि प्रॉप्स और नेक्स्टप्रॉप्स एक ही हैं, renderबिल्कुल भी नहीं कहा जाएगा।

प्रतिक्रिया में "शुद्ध" की परिभाषा पर नोट्स:

सामान्य तौर पर, "शुद्ध फ़ंक्शन" एक ऐसा फ़ंक्शन होता है जो समान इनपुट को दिए गए परिणाम के लिए हमेशा मूल्यांकन करता है। आउटपुट (रिएक्ट के लिए, जो कि renderविधि द्वारा लौटाया गया है ) किसी भी इतिहास / स्थिति पर निर्भर नहीं करता है और इसका कोई भी साइड-इफेक्ट नहीं है (ऑपरेशन जो "फ़ंक्शन के बाहर" दुनिया को बदलते हैं)।

प्रतिक्रिया में, स्टेटलेस घटकों को आवश्यक रूप से शुद्ध घटकों के अनुसार ऊपर परिभाषा के अनुसार नहीं कहा जाता है यदि आप "स्टेटलेस" एक घटक कहते हैं जो कभी कॉल नहीं करता है this.setStateऔर जो इसका उपयोग नहीं करता है this.state

वास्तव में, एक में PureComponent, आप अभी भी जीवनचक्र विधियों के दौरान साइड-इफेक्ट कर सकते हैं। उदाहरण के लिए आप अंदर एक अजाक्स अनुरोध भेज componentDidMountसकते हैं या आप कुछ डॉम गणना को गतिशील रूप से एक div की ऊंचाई को समायोजित करने के लिए कर सकते हैं render

"गूंगा घटकों" की परिभाषा का अधिक "व्यावहारिक" अर्थ है (कम से कम मेरी समझ में): एक गूंगा घटक "को बताया जाता है" एक मूल घटक के माध्यम से प्रॉप्स के माध्यम से क्या करना है, और चीजों को कैसे करना है पता नहीं है, लेकिन रंगमंच की सामग्री का उपयोग करता है इसके बजाय कॉलबैक।

"स्मार्ट" का उदाहरण AvatarComponent:

class AvatarComponent extends Component {
    expandAvatar () {
        this.setState({ loading: true });
        sendAjaxRequest(...).then(() => {
            this.setState({ loading: false });
        });
    }        

    render () {
        <div onClick={this.expandAvatar}>
            <img src={this.props.username} />
        </div>
    }
}

"गूंगा" का उदाहरण AvatarComponent:

class AvatarComponent extends Component {
    render () {
        <div onClick={this.props.onExpandAvatar}>
            {this.props.loading && <div className="spinner" />}
            <img src={this.props.username} />
        </div>
    }
}

अंत में मैं कहूंगा कि "गूंगा", "स्टेटलेस" और "शुद्ध" काफी अलग अवधारणाएं हैं जो कभी-कभी ओवरलैप कर सकती हैं, लेकिन जरूरी नहीं कि ज्यादातर आपके उपयोग के मामले पर निर्भर करें।


1
मैं वास्तव में आपके उत्तर और आपके द्वारा साझा किए गए ज्ञान की सराहना करता हूं। लेकिन मेरा असली सवाल यह है कि हमें कब चुनना चाहिए? । आपके उत्तर में वर्णित उसी उदाहरण के लिए, मुझे इसे कैसे परिभाषित करना चाहिए? क्या यह कार्यात्मक स्टेटलेस घटक होना चाहिए (यदि ऐसा है तो क्यों?), या PureComponent (क्यों?) का विस्तार या घटक वर्ग (फिर क्यों?) का विस्तार करें। आप कैसे तय करते हैं, आप हमारे घटकों के उद्देश्य / आकार / सहारा / व्यवहार के आधार पर इन तीनों के बीच कैसे चयन करते हैं ?
यदु किरन

1
कोई दिक्कत नहीं है। फंक्शनल स्टेटलेस कंपोनेंट के लिए, वहाँ एक पेशेवरों / विपक्ष की सूची है जिसे मैं तय करने के लिए विचार कर सकता हूं कि क्या यह एक अच्छा फिट होगा। क्या इसका जवाब आपको पहली बार मिलता है? मैं पसंद सवाल को थोड़ा और संबोधित करने की कोशिश करने जा रहा हूं।
fabio.sussetto

2
जब माता-पिता घटक अद्यतन हो जाते हैं, तब भी कार्यात्मक घटक हमेशा पुनः प्रदान किए जाते हैं, भले ही वे बिल्कुल भी उपयोग न करें propsउदाहरण है
एलेक्सएम

1
यह सबसे व्यापक उत्तरों में से एक है जो मैंने काफी समय में पढ़ा है। अच्छा कार्य। बहुत पहले वाक्य के बारे में एक टिप्पणी: जब विस्तार PureComponent, आपको लागू नहीं करना चाहिए shouldComponentUpdate()। यदि आप वास्तव में ऐसा करते हैं तो आपको एक चेतावनी देखनी चाहिए।
jjramos

1
वास्तविक प्रदर्शन लाभ के लिए आपको उन PureComponentघटकों के लिए उपयोग करने का प्रयास करना चाहिए जिनके पास ऑब्जेक्ट / सरणी गुण हैं। निश्चित रूप से आपको पता होना चाहिए कि क्या हो रहा है। अगर मैं सही तरीके से समझूं, अगर आप सीधे प्रॉप्स / स्टेट को म्यूट नहीं कर रहे हैं (जो रिएक्ट आपको चेतावनी के साथ करने से रोकने की कोशिश करता है) या बाहरी लाइब्रेरी के माध्यम से, तो आपको हर जगह बहुत ज्यादा इस्तेमाल PureComponentकरने के बजाय ठीक होना चाहिए Component... अपवाद के साथ बहुत सरल घटकों में जहां यह वास्तव में तेजी से हो सकता है इसका उपयोग नहीं करना है - समाचार देखें ।comcomatorator.com
मैट ब्राउन

28

मैं प्रतिक्रिया से अधिक प्रतिभाशाली नहीं हूं, लेकिन मेरी समझ से हम निम्नलिखित स्थितियों में प्रत्येक घटक का उपयोग कर सकते हैं

  1. स्टेटलेस कंपोनेंट - ये ऐसे कंपोनेंट होते हैं जिनमें जीवन-चक्र नहीं होता है, इसलिए इन कंपोनेंट्स का इस्तेमाल पेरेंट कंपोनेंट के रिपीट एलिमेंट को रेंडर करने में किया जाना चाहिए, जैसे कि टेक्स्ट लिस्ट को रेंडर करना, जिसमें सिर्फ इन्फॉर्मेशन दिखाई देती है और परफॉर्म करने के लिए कोई एक्शन नहीं होता।

  2. शुद्ध घटक - ये वे वस्तुएं हैं जिनका जीवन-चक्र है और वे हमेशा उसी परिणाम को वापस करेंगे जब प्रॉप्स का एक विशिष्ट सेट दिया जाता है। उन घटकों का उपयोग परिणामों की सूची या एक विशिष्ट ऑब्जेक्ट डेटा को प्रदर्शित करते समय किया जा सकता है, जिसमें जटिल बाल तत्व नहीं होते हैं और केवल संचालन करने के लिए उपयोग किया जाता है। उपयोगकर्ता कार्ड या उत्पाद कार्ड की सूची (मूल उत्पाद की जानकारी) और केवल उपयोगकर्ता द्वारा प्रदर्शन की जाने वाली सूची प्रदर्शित हो सकती है, विस्तार पृष्ठ देखने के लिए क्लिक करें या कार्ट में जोड़ें।

  3. सामान्य घटक या जटिल घटक - मैंने जटिल घटक शब्द का उपयोग किया क्योंकि वे आमतौर पर पृष्ठ स्तर के घटक होते हैं और इसमें बहुत सारे बच्चे घटक होते हैं और चूंकि प्रत्येक बच्चा अपने स्वयं के अनूठे तरीके से व्यवहार कर सकता है, इसलिए आप यह सुनिश्चित नहीं कर सकते कि यह 100% है दिए गए राज्य पर समान परिणाम प्रस्तुत करें। जैसा कि मैंने कहा आमतौर पर इनका उपयोग कंटेनर घटकों के रूप में किया जाना चाहिए


1
यह दृष्टिकोण काम कर सकता है, लेकिन आप बड़े प्रदर्शन लाभ से गायब हो सकते हैं। PureComponentअपने पदानुक्रम के शीर्ष के पास रूट-स्तरीय घटकों और घटकों का उपयोग करना आमतौर पर होता है जहां आपको सबसे बड़ा प्रदर्शन लाभ मिलेगा। बेशक, आपको सही तरीके से काम करने के लिए शुद्ध घटकों के लिए उत्परिवर्तित करने वाले प्रॉप्स और स्थिति से सीधे बचने की आवश्यकता है, लेकिन ऑब्जेक्ट्स को सीधे म्यूट करना किसी भी तरह से रिएक्ट में एक विरोधी पैटर्न है।
मैट ब्राउन

5
  • React.Componentडिफ़ॉल्ट "सामान्य" घटक है। आप उन्हें classकीवर्ड का उपयोग करते हुए घोषित करते हैं extends React.Component। उन्हें एक वर्ग के रूप में सोचें, जीवन चक्र विधियों, घटना संचालकों और जो भी तरीकों के साथ।

  • React.PureComponentयह एक फ़ंक्शन के साथ React.Componentलागू shouldComponentUpdate()होता है जो इसकी तुलना के उथले तुलना करता है propsऔर stateforceUpdate()यदि आपको पता है कि घटक के पास प्रॉप्स या स्टेट नेस्टेड डेटा है जिसे आपने बदल दिया है और आप फिर से रेंडर करना चाहते हैं तो आपको इसका उपयोग करना होगा। यदि आप सरणियों या उन वस्तुओं को पास करते हैं जिन्हें आप अपने राज्य परिवर्तन में सेट करते हैं या सेट करते हैं तो आपको पुन: रेंडर करने के लिए घटकों की आवश्यकता होती है इसलिए वे महान नहीं हैं।

  • कार्यात्मक घटक वे होते हैं जिनमें जीवनचक्र कार्य नहीं होते हैं। वे माना जाता है कि स्टेटलेस हैं, लेकिन वे इतने अच्छे और साफ हैं कि हमारे पास अब हुक (16.8 रिएक्ट के बाद) है, ताकि आप अभी भी एक राज्य कर सकें। इसलिए मुझे लगता है कि वे सिर्फ "स्वच्छ घटक" हैं।

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