ReactJS - क्या रेंडर को किसी भी समय "सेटस्टेट" कहा जाता है?


503

क्या प्रतिक्रिया हर बार सभी घटकों और उप घटकों को फिर से प्रस्तुत करती setStateहै?

यदि हां, तो क्यों? मैंने सोचा कि विचार यह था कि रिएक्ट केवल आवश्यकतानुसार कम ही प्रदान किया गया - जब राज्य बदल गया।

निम्नलिखित सरल उदाहरण में, दोनों वर्गों को फिर से प्रस्तुत किया जाता है जब पाठ पर क्लिक किया जाता है, इस तथ्य के बावजूद कि राज्य बाद के क्लिकों में नहीं बदलता है, क्योंकि ऑनक्लिक हैंडलर हमेशा stateएक ही मूल्य पर सेट होता है :

this.setState({'test':'me'});

मुझे उम्मीद है कि रेंडर केवल तभी होगा जब stateडेटा बदल गया हो।

जेएस फिडेल और एम्बेडेड स्निपेट के रूप में उदाहरण का कोड यहां दिया गया है :

var TimeInChild = React.createClass({
    render: function() {
        var t = new Date().getTime();

        return (
            <p>Time in child:{t}</p>
        );
    }
});

var Main = React.createClass({
    onTest: function() {
        this.setState({'test':'me'});
    },

    render: function() {
        var currentTime = new Date().getTime();

        return (
            <div onClick={this.onTest}>
            <p>Time in main:{currentTime}</p>
            <p>Click me to update time</p>
            <TimeInChild/>
            </div>
        );
    }
});

ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>

[1]: http://jsfiddle.net/fp2tncmb/2/

मेरे पास एक ही मुद्दा था, मुझे सटीक समाधान नहीं पता है। लेकिन मैंने हमेशा की तरह काम करना शुरू कर दिया घटक से अवांछित कोड को साफ किया था।
जैसन

मैं यह बताना चाहूंगा कि आपके उदाहरण में - क्योंकि आपका तत्व कैसे बनाया गया है, यह केवल एक अद्वितीय स्थिति पर निर्भर नहीं करता है - setState()डमी डेटा के साथ भी कॉल करने से तत्व अलग तरीके से प्रस्तुत होता है, इसलिए मैं हां कहूंगा। बिल्कुल इसे अपनी वस्तु को फिर से प्रस्तुत करने का प्रयास करना चाहिए जब कुछ बदल गया हो सकता है क्योंकि अन्यथा आपका डेमो - यह मानकर कि यह इच्छित व्यवहार था - काम नहीं करेगा!
तदह मैकडॉनल्ड्स-जेनसेन

आप सही हो सकते हैं @ TadhgMcDonald-Jensen - लेकिन मेरी समझ से, React ने इसे पहली बार प्रस्तुत किया होगा (क्योंकि पहली बार कुछ भी नहीं होने से राज्य में बदलाव होता है), फिर कभी फिर से प्रस्तुत नहीं करना पड़ा। हालाँकि, मैं गलत था - जैसा कि यह दिखता है कि रिएक्ट के लिए आपको अपनी shouldComponentUpdateविधि लिखने की आवश्यकता होती है , जिसे मैंने माना कि इसका एक सरल संस्करण पहले से ही रिएक्ट में शामिल होना चाहिए। प्रतिक्रिया में शामिल डिफ़ॉल्ट संस्करण की तरह लगता है बस रिटर्न true- जो घटक को हर बार फिर से प्रस्तुत करने के लिए मजबूर करता है।
ब्रैड पार्क

हां, लेकिन इसे केवल वर्चुअल डोम में फिर से प्रस्तुत करने की आवश्यकता है फिर यह केवल वास्तविक डोम को बदलता है अगर घटक को अलग तरीके से प्रस्तुत किया जाता है। वर्चुअल डोम के अपडेट आम तौर पर नगण्य होते हैं (वास्तविक स्क्रीन पर चीजों को संशोधित करने की तुलना में कम से कम) इसलिए हर बार रेंडर कॉल करने से इसे अपडेट करने की आवश्यकता हो सकती है, यह देखते हुए कि कोई भी परिवर्तन बहुत महंगा नहीं हुआ है और यह मानने की तुलना में सुरक्षित है कि इसे प्रस्तुत करना चाहिए।
तदह मैकडॉनल्ड्स-जेनसेन

जवाबों:


570

क्या रिएक्ट सभी घटकों और उप-घटकों को हर बार सेटस्टैट पर फिर से प्रस्तुत करता है?

डिफ़ॉल्ट रूप से - हाँ।

एक विधि है बूलियन shouldComponentUpdate (ऑब्जेक्ट नेक्स्टप्रॉप्स, ऑब्जेक्ट नेक्स्टस्टेट) , प्रत्येक घटक में यह विधि है और यह निर्धारित करने के लिए "घटक अपडेट ( फ़ंक्शन रेंडर फ़ंक्शन) चलाना चाहिए ?" हर बार जब आप राज्य बदलते हैं या मूल घटक से नए प्रॉप्स पास करते हैं।

आप अपने घटक के लिए shouldComponentUpdate पद्धति का अपना कार्यान्वयन लिख सकते हैं, लेकिन डिफ़ॉल्ट कार्यान्वयन हमेशा सही होता है - मतलब हमेशा रेंडर फ़ंक्शन को फिर से चलाना।

आधिकारिक डॉक्स से उद्धरण http://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate

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

आपके प्रश्न का अगला भाग:

यदि हां, तो क्यों? मुझे लगता है कि विचार यह था कि रिएक्ट केवल आवश्यकतानुसार ही प्रदान किया जाता है - जब राज्य बदल गया।

"रेंडर" को हम क्या कह सकते हैं, इसके दो चरण हैं:

  1. वर्चुअल डोम रेंडर: जब रेंडर मेथड कहा जाता है तो यह घटक की एक नई वर्चुअल डोम संरचना लौटाता है । जैसा कि मैंने पहले उल्लेख किया है, इस रेंडर विधि को हमेशा कहा जाता है जब आप सेटस्टैट () कहते हैं , क्योंकि shouldComponentUpdate हमेशा डिफ़ॉल्ट रूप से सही होता है। तो, डिफ़ॉल्ट रूप से, प्रतिक्रिया में यहाँ कोई अनुकूलन नहीं है।

  2. Native DOM रेंडर: रिएक्ट आपके ब्राउज़र में वास्तविक DOM नोड्स को केवल तब ही बदल देता है, जब वे वर्चुअल DOM में और आवश्यकतानुसार बहुत कम बदल गए हों - यह महान React की विशेषता है जो वास्तविक DOM उत्परिवर्तन का अनुकूलन करता है और React को तेज बनाता है।


47
महान व्याख्या! और एक बात जो वास्तव में रिएक्ट बनाती है वह इस मामले में अभी भी चमक रही है कि यह वास्तविक डोम को तब तक नहीं बदलती है जब तक कि वर्चुअल डोम को बदल नहीं दिया गया हो। इसलिए अगर मेरे रेंडर फ़ंक्शन एक ही चीज़ को 2 बार पंक्ति में लौटाते हैं, तो वास्तविक DOM बिल्कुल भी परिवर्तित नहीं होता है ... धन्यवाद!
ब्रैड पार्क

1
मुझे लगता है कि @tungd सही है - नीचे उसका उत्तर देखें। यह घटकों के बीच माता-पिता के बच्चे के संबंध का भी मामला है। उदाहरण के लिए यदि TimeInChild Main का भाई है तो उसका रेंडर () अनावश्यक रूप से नहीं कहा जाएगा।
gvlax 12

2
यदि आपके राज्य में एक अपेक्षाकृत बड़ी जावास्क्रिप्ट ऑब्जेक्ट (~ 1k कुल गुण) है, जो घटकों के एक बड़े पेड़ के रूप में प्रदान की जाती है (~ 100 कुल) ... आपको रेंडर फ़ंक्शंस को वर्चुअल डोम का निर्माण करने देना चाहिए, या आपको सेट करने से पहले करना चाहिए। राज्य, नए राज्य की तुलना पुराने से मैन्युअल रूप से करें और केवल तभी कॉल करें setStateजब आपको पता चले कि इसमें कोई अंतर है? यदि हां, तो यह सबसे अच्छा कैसे किया जाए - json स्ट्रिंग्स की तुलना करें, ऑब्जेक्ट हैश की तुलना करें, ...?
विंसेंट सेल्स

1
@Petr, लेकिन भले ही प्रतिक्रिया वर्चुअल डोम को फिर से संगठित करती हो, अगर पुराना वर्चुअल डोम नए वर्चुअल डोम के समान है, तो ब्राउज़र डोम को छुआ नहीं जाएगा, है ना?
जसकी

3
इसके अलावा, React.PureComponent ( reactjs.org/docs/react-api.html#reactpurecomponent ) का उपयोग करके देखें । यह केवल अद्यतन (पुनः रेंडर) करता है यदि घटक की स्थिति या रंगमंच वास्तव में बदल गए हैं। हालांकि, तुलना करें कि तुलना उथली है।
डिबेटर

105

नहीं, जब राज्य बदलता है तो रिएक्ट सब कुछ प्रस्तुत नहीं करता है।

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

  • प्रतिक्रिया राज्य डेटा की तुलना नहीं करती है। जब setStateकहा जाता है, तो यह घटक को गंदे के रूप में चिह्नित करता है (जिसका अर्थ है कि इसे फिर से प्रस्तुत करना होगा)। ध्यान देने वाली महत्वपूर्ण बात यह है कि यद्यपि renderघटक की विधि को कहा जाता है, वास्तविक DOM केवल तभी अपडेट किया जाता है जब आउटपुट वर्तमान DOM ट्री (वर्चुअल DOM ट्री और दस्तावेज़ DOM ट्री के बीच भिन्न होता है उर्फ) से भिन्न होता है। आपके उदाहरण में, भले ही stateडेटा नहीं बदला हो, अंतिम परिवर्तन का समय था, वर्चुअल डोम को दस्तावेज़ के DOM से अलग बनाता है, इसलिए HTML को अपडेट क्यों किया जाता है।


हां, यह सही उत्तर है। प्रयोग के रूप में React.renderComponent (<div> <Main /> <TimeInChild /> </ div>, document.body) के रूप में अंतिम पंक्ति को संशोधित करें ; और मुख्य घटक के रेंडर () के शरीर से <TimeInChild /> को हटा दें । प्रस्तुत करना () की TimeInChild डिफ़ॉल्ट रूप से नहीं कहा जा जाएगा क्योंकि यह का एक बच्चा नहीं है मुख्य किसी भी अधिक।
ग्व्लैक्स

धन्यवाद, इस तरह से सामान थोड़ा मुश्किल है, यही कारण है कि रिएक्ट लेखकों ने सिफारिश की कि render()विधि "शुद्ध" होनी चाहिए - बाहरी राज्य से स्वतंत्र।
1929

3
@ टंगड, इसका क्या मतलब है some branch is moved to another root? आप क्या कहते हैं branch? आप क्या कहते हैं root?
ग्रीन

2
मैं वास्तव में सही के रूप में चिह्नित उत्तर को पसंद करता हूं। मैं मूल, 'वास्तविक', पक्ष ... पर 'प्रतिपादन' की आपकी व्याख्या को समझता हूं, लेकिन यदि आप इसे प्रतिक्रिया-मूल पक्ष से देखते हैं तो आपको यह कहना होगा कि यह फिर से प्रस्तुत होता है। सौभाग्य से यह निर्धारित करने के लिए काफी स्मार्ट है कि वास्तव में क्या बदल गया है और केवल इन चीजों को अपडेट करें। यह उत्तर नए उपयोगकर्ताओं के लिए भ्रामक हो सकता है, पहले आप नहीं कहते हैं, और फिर आप समझाते हैं कि चीजें प्रदान की जाती हैं ...
WiRa

1
@tungd क्या आप ग्रीन के सवाल को समझ सकते हैंwhat does it mean some branch is moved to another root? What do you call branch? What do you call root?
madhu131313

7

भले ही यह कई अन्य उत्तरों में बताया गया है, घटक या तो होना चाहिए:

  • shouldComponentUpdateराज्य या संपत्तियों में परिवर्तन होने पर ही रेंडर करने के लिए लागू करें

  • एक PureComponent को विस्तारित करने के लिए स्विच करें , जो पहले से ही shouldComponentUpdateउथले तुलना के लिए आंतरिक रूप से एक विधि लागू करता है ।

यहां एक उदाहरण दिया गया है जो उपयोग करता है shouldComponentUpdate, जो केवल इस सरल उपयोग के मामले और प्रदर्शन उद्देश्यों के लिए काम करता है। जब इसका उपयोग किया जाता है, तो घटक अब प्रत्येक क्लिक पर खुद को फिर से प्रस्तुत नहीं करता है, और पहली बार प्रदर्शित होने पर प्रदान किया जाता है, और इसके बाद एक बार क्लिक किया जाता है।

var TimeInChild = React.createClass({
    render: function() {
        var t = new Date().getTime();

        return (
            <p>Time in child:{t}</p>
        );
    }
});

var Main = React.createClass({
    onTest: function() {
        this.setState({'test':'me'});
    },

    shouldComponentUpdate: function(nextProps, nextState) {
      if (this.state == null)
        return true;
  
      if (this.state.test == nextState.test)
        return false;
        
      return true;
  },

    render: function() {
        var currentTime = new Date().getTime();

        return (
            <div onClick={this.onTest}>
            <p>Time in main:{currentTime}</p>
            <p>Click me to update time</p>
            <TimeInChild/>
            </div>
        );
    }
});

ReactDOM.render(<Main/>, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>



3

"खोया अद्यतन" का एक और कारण अगला हो सकता है:

  • यदि स्थिर getDerivedStateFromProps को परिभाषित किया जाता है, तो यह आधिकारिक दस्तावेज़ीकरण https://reactjs.org/docs/react-component.html#updating के अनुसार हर अद्यतन प्रक्रिया में पुनर्मिलन होता है ।
  • इसलिए अगर वह राज्य मूल्य शुरुआत से ही प्रॉपर से आता है तो वह हर अपडेट में ओवरराइट हो जाता है।

यदि यह समस्या है, तो यू अपडेट के दौरान राज्य की स्थापना से बच सकता है, आपको इस तरह राज्य पैरामीटर मान की जांच करनी चाहिए

static getDerivedStateFromProps(props: TimeCorrectionProps, state: TimeCorrectionState): TimeCorrectionState {
   return state ? state : {disable: false, timeCorrection: props.timeCorrection};
}

एक अन्य समाधान राज्य के लिए एक प्रारंभिक संपत्ति जोड़ रहा है, और इसे पहली बार में सेट करें (यदि राज्य गैर-शून्य मान के लिए प्रारंभ किया गया है)।


0

सभी अवयव नहीं।

stateघटक दिखता में पूरे एपीपी के राज्य के झरना के स्रोत की तरह।

इसलिए परिवर्तन होता है जहां से सेटस्टेट को बुलाया जाता है। तब के पेड़ को rendersवहां से बुलाया जाता है। यदि आपने शुद्ध घटक का उपयोग किया है, तो renderछोड़ दिया जाएगा।

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