सिंक के बजाए पुन: अभिकर्मक Async में क्यों सेट किया गया है?


126

मैंने अभी-अभी पाया है कि this.setState()किसी घटक में प्रतिक्रिया फलन में अतुल्यकालिक होता है या उस फ़ंक्शन के पूरा होने के बाद उसे कॉल किया जाता है जिसे यह कहा जाता था।

अब मैंने इस ब्लॉग को खोजा और पाया ( सेटस्टेट () स्टेट म्यूटेशन ऑपरेशन हो सकता है सिंक्रोनस इन रिएक्टजेएस )

यहाँ उन्होंने पाया कि setStateasync (जिसे स्टैक खाली है) या सिंक (जैसे ही कॉल किया जाता है) इस बात पर निर्भर करता है कि राज्य के परिवर्तन को कैसे ट्रिगर किया गया था।

अब इन दोनों चीजों को पचाना मुश्किल है

  1. ब्लॉग में setStateफंक्शन को फंक्शन के अंदर कहा जाता है updateState, लेकिन जो updateStateफंक्शन शुरू हो जाता है, वह ऐसा नहीं है जिसके बारे में किसी फंक्शन को पता हो।
  2. वे setStateasync क्यों करेंगे क्योंकि JS सिंगल थ्रेडेड लैंग्वेज है और यह सेटस्टेट वेबएपीआई या सर्वर कॉल नहीं है इसलिए जेएस के थ्रेड पर ही काम करना होगा। क्या वे ऐसा कर रहे हैं ताकि री-रेंडरिंग सभी ईवेंट श्रोताओं और सामान को रोक न दे, या कुछ अन्य डिजाइन मुद्दा है।


1
मैंने आज एक लेख लिखा है जो चारों ओर की जलवायु का थोड़ा सा वर्णन करने में मदद करता है setState: medium.com/@agm1984/…
agm1984

जवाबों:


156

राज्य मान के अद्यतन होने के बाद आप किसी फ़ंक्शन को कॉल कर सकते हैं:

this.setState({foo: 'bar'}, () => { 
    // Do something here. 
});

इसके अलावा, यदि आपके पास एक साथ अपडेट करने के लिए बहुत सारे राज्य हैं, तो उन सभी को एक ही समूह में रखें setState:

के बजाय:

this.setState({foo: "one"}, () => {
    this.setState({bar: "two"});
});

बस यह करें:

this.setState({
    foo: "one",
    bar: "two"
});

17
हाँ ठीक है, हमें एक कॉलबैक फ़ंक्शन मिला है जिसका उपयोग हम कर सकते हैं लेकिन सवाल नहीं है।
अनूप

12
उम्मीद है कि यह किसी और की मदद करेगा कि कैसे इस सवाल पर ठोकर खाई।
जोएटाइडे


97

1) setStateक्रियाएं अतुल्यकालिक हैं और प्रदर्शन लाभ के लिए बैचेन हैं। के प्रलेखन में यह समझाया गया है setState

setState () तुरंत इसे बदल नहीं देता है। इसे स्थिर करें, लेकिन एक लंबित राज्य संक्रमण बनाता है। इस पद्धति पर कॉल करने के बाद इसे एक्सेस करना संभवत: मौजूदा मान को लौटा सकता है। सेटस्टैट करने के लिए कॉल के सिंक्रोनस ऑपरेशन की कोई गारंटी नहीं है और प्रदर्शन लाभ के लिए कॉल को बैच किया जा सकता है।


2) वे जेनेट एक सिंगल थ्रेडेड भाषा के रूप में सेट-अप एस्स्टेक क्यों करेंगे और यह setStateएक वेबएपीआई या सर्वर कॉल नहीं है?

ऐसा इसलिए है क्योंकि setStateराज्य को बदल देता है और पुनर्जन्म का कारण बनता है। यह एक महंगा ऑपरेशन हो सकता है और इसे तुल्यकालिक बनाने से ब्राउज़र अप्रतिसादी हो सकता है।

इस प्रकार setState कॉल अतुल्यकालिक के साथ-साथ बेहतर UI अनुभव और प्रदर्शन के लिए बैचबद्ध हैं।


59
यदि आपको एक सेटस्टैट कॉल किए जाने के बाद घटनाओं का क्रम सुनिश्चित करने की आवश्यकता है, तो आप कॉलबैक फ़ंक्शन पास कर सकते हैं। this.setState({ something: true }, () => console.log(this.state))
इयक्स

1
शुक्रिया @Sachin स्पष्टीकरण के लिए। हालाँकि, मुझे अभी भी संदेह है, क्या यह समकालिक हो सकता है जैसा कि ब्लॉग बताता है?
अजय गौड़

2
प्रतिक्रिया में एक और बेवकूफ डिजाइन निर्णय। राज्य अपडेट को सिंक्रोनस, और रेंडरिंग एसिंक्रोनस बनाएं। आप रेंडरिंग बैच कर सकते हैं, लेकिन मैं दौड़ की स्थितियों से निपटने के लिए बिना राज्य के चर के रूप में आदिम के रूप में कुछ सेट करने में सक्षम होना चाहता हूं।
इग-देव

क्यों नहीं विकल्प को async या सिंक बनाने के लिए सेट करने की अनुमति दें? यह एक उपयोगी फीचर होगा
Randall Coding

जाहिर है, मैं प्रतिक्रिया टीम में नहीं हूं, लेकिन एक कारण, मेरी राय में राज्य को async अपडेट करने के लिए ब्राउज़र सिंगल थ्रेडेड हैं। सिंक ऑपरेशन यूआई को गैर-जिम्मेदार बना सकते हैं और यूआई के लिए अच्छे उम्मीदवार नहीं हैं।
सचिन

16

मुझे पता है कि यह प्रश्न पुराना है, लेकिन यह कई प्रतिक्रियाशील उपयोगकर्ताओं के लिए लंबे समय से भ्रम की स्थिति पैदा कर रहा है, जिनमें मैं भी शामिल हूं। हाल ही में दान अब्रामोव (प्रतिक्रिया टीम से) ने इस बारे में एक शानदार विवरण लिखा है कि प्रकृति की प्रकृति क्यों setStateहै:

https://github.com/facebook/react/issues/11527#issuecomment-360199710

setStateअतुल्यकालिक होने का मतलब है, और डैन अब्रामोव द्वारा लिंक किए गए स्पष्टीकरण में इसके कुछ बहुत अच्छे कारण हैं। इसका मतलब यह नहीं है कि यह हमेशा अतुल्यकालिक होगा - इसका मुख्य रूप से मतलब है कि आप सिर्फ इस पर तुल्यकालिक नहीं हो सकते । ReactJS परिदृश्य में कई चर को ध्यान में रखता है जो आप राज्य में बदल रहे हैं, यह तय करने के लिए कि stateवास्तव में कब अपडेट किया जाना चाहिए और आपके घटक ने फिर से रेंडर किया।
इसे प्रदर्शित करने के लिए एक सरल उदाहरण यह है कि यदि आप setStateउपयोगकर्ता की कार्रवाई पर प्रतिक्रिया के रूप में कॉल करते हैं, तो stateसंभवतः तुरंत अपडेट किया जाएगा (हालांकि, फिर से, आप इस पर भरोसा नहीं कर सकते हैं), इसलिए उपयोगकर्ता को कोई देरी महसूस नहीं होगी , लेकिन अगर आप फोन करते हैंsetState अजाक्स कॉल प्रतिक्रिया या उपयोगकर्ता द्वारा ट्रिगर नहीं की गई किसी अन्य घटना की प्रतिक्रिया में, तब स्थिति को थोड़ी देरी से अपडेट किया जा सकता है, क्योंकि उपयोगकर्ता वास्तव में इस देरी को महसूस नहीं करेगा, और यह प्रतीक्षा करके प्रदर्शन में सुधार करेगा। बैच एक साथ कई राज्य अद्यतन करता है और DOM को कम बार रेंडर करता है।


हां किसी भी उत्तरदाता को सही के रूप में चिह्नित नहीं किया है। लोग पोस्ट कर रहे हैं कि इसके आसपास कैसे पहुंचा जाए। पूछे गए सवाल का जवाब नहीं। यह लेख अच्छा लगा।
अनूप

@Anup उत्तर 'async' या 'सिंक' की तुलना में थोड़ा अधिक जटिल है। इसे हमेशा 'async' के रूप में माना जाना चाहिए, लेकिन कुछ मामलों में 'सिंक' कार्य कर सकता है। मुझे आशा है कि मैंने आपके लिए कुछ प्रकाश डाला।
जिलिब

8

अच्छा लेख यहाँ https://github.com/vasanthk/react-bits/blob/master/patterns/27.passing-function-to-setState.md

// assuming this.state.count === 0
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
// this.state.count === 1, not 3

Solution
this.setState((prevState, props) => ({
  count: prevState.count + props.increment
}));

या कॉलबैक पास करें this.setState ({.....},callback)

https://medium.com/javascript-scene/setstate-gate-abc10a9b2d82 https://medium.freecodecamp.org/functional-setstate-is-the-future-of-react-374f30401b6b



1

कुछ घटक में एक काउंटर बढ़ाने की कल्पना करें:

  class SomeComponent extends Component{

    state = {
      updatedByDiv: '',
      updatedByBtn: '',
      counter: 0
    }

    divCountHandler = () => {
      this.setState({
        updatedByDiv: 'Div',
        counter: this.state.counter + 1
      });
      console.log('divCountHandler executed');
    }

    btnCountHandler = () => {
      this.setState({
        updatedByBtn: 'Button',
        counter: this.state.counter + 1
      });
      console.log('btnCountHandler executed');
    }
    ...
    ...
    render(){
      return (
        ...
        // a parent div
        <div onClick={this.divCountHandler}>
          // a child button
          <button onClick={this.btnCountHandler}>Increment Count</button>
        </div>
        ...
      )
    }
  }

माता-पिता और बाल घटकों दोनों के लिए एक गिनती हैंडलर जुड़ा हुआ है। यह जानबूझकर किया जाता है इसलिए हम सेटस्टैट () को एक ही क्लिक ईवेंट बबलिंग संदर्भ में दो बार निष्पादित कर सकते हैं, लेकिन 2 अलग-अलग हैंडलर के भीतर से।

जैसा कि हम कल्पना करेंगे, बटन पर एक सिंगल क्लिक इवेंट अब इन दोनों हैंडलर को ट्रिगर करेगा क्योंकि ईवेंट बबलिंग चरण के दौरान लक्ष्य से सबसे बाहरी कंटेनर तक बुलबुले।

इसलिए btnCountHandler () पहले निष्पादित करता है, 1 की गिनती में वृद्धि करने की अपेक्षा करता है और फिर divCountHandler () निष्पादित करता है, गणना को 2 तक बढ़ाने की अपेक्षा करता है।

हालाँकि आप केवल 1 में वृद्धि की गणना करते हैं क्योंकि आप रिएक्टर डेवलपर टूल में निरीक्षण कर सकते हैं।

यह साबित करता है कि प्रतिक्रिया

  • सभी सेटस्टेट कॉल को कतार में रखता है

  • संदर्भ में अंतिम विधि (इस मामले में divCountHandler) निष्पादित करने के बाद इस कतार में वापस आ जाता है

  • एक ही संदर्भ में कई सेटस्टैट कॉल के भीतर होने वाली सभी ऑब्जेक्ट म्यूटेशन को मर्ज करता है (एक एकल चरण के लिए सभी विधि कॉल उदाहरण के लिए समान है) एक एकल ऑब्जेक्ट म्यूटेशन सिंटैक्स में (विलय करना समझ में आता है क्योंकि यही कारण है कि हम राज्य को स्वतंत्र रूप से अपडेट कर सकते हैं सेटस्टैट में () पहले स्थान पर

  • और इसे एक सिंगल सेटस्टैट () में कई सेटस्टेट () कॉल के कारण फिर से रेंडर करने से रोकने के लिए (यह बैचिंग का एक बहुत ही आदिम वर्णन है)।

प्रतिक्रिया द्वारा संचालित परिणामी कोड:

this.setState({
  updatedByDiv: 'Div',
  updatedByBtn: 'Button',
  counter: this.state.counter + 1
})

इस व्यवहार को रोकने के लिए, सेटस्टैट विधि में तर्क के रूप में ऑब्जेक्ट्स को पास करने के बजाय, कॉलबैक को पास किया जाता है।

    divCountHandler = () => {
          this.setState((prevState, props) => {
            return {
              updatedByDiv: 'Div',
              counter: prevState.counter + 1
            };
          });
          console.log('divCountHandler executed');
        }

    btnCountHandler = () => {
          this.setState((prevState, props) => {
            return {
              updatedByBtn: 'Button',
              counter: prevState.counter + 1
            };
          });
      console.log('btnCountHandler executed');
    }

अंतिम विधि के बाद निष्पादन समाप्त हो जाता है और जब प्रतिक्रिया सेटस्टैट कतार को संसाधित करने के लिए वापस आती है, तो यह पिछले घटक स्थिति में गुजरते हुए, प्रत्येक सेटस्टेट कतार के लिए कॉलबैक को कॉल करता है।

इस तरह से प्रतिक्रिया यह सुनिश्चित करती है कि कतार में अंतिम कॉलबैक उस स्थिति को अपडेट करने के लिए मिलता है जो उसके सभी पिछले समकक्षों ने हाथ रखा है।


0

हां, setState () अतुल्यकालिक है।

लिंक से: https://reactjs.org/docs/react-component.html#setstate

  • प्रतिक्रिया की गारंटी नहीं है कि राज्य परिवर्तन तुरंत लागू होते हैं।
  • setState () हमेशा घटक को तुरंत अपडेट नहीं करता है।
  • घटक को अद्यतन करने के लिए तत्काल आदेश के बजाय सेटस्टैट () के बारे में सोचें।

क्योंकि वे
इस लिंक से सोचते हैं : https://github.com/facebook/react/issues/11527#issuecomment-360199710

... हम इस बात से सहमत हैं कि कई मामलों में सेटस्ट्रेट () फिर से रेंडर करना अक्षम्य होगा

असिंक्रोनस सेटस्टैट () दुर्भाग्य से शुरू होने और यहां तक ​​कि दुर्भाग्य से अनुभव किए गए लोगों के लिए जीवन को बहुत कठिन बनाता है:
- अप्रत्याशित प्रतिपादन मुद्दे: विलंबित प्रतिपादन या कोई प्रतिपादन नहीं (कार्यक्रम तर्क के आधार पर)
- पासिंग पैरामीटर
अन्य मुद्दों के बीच एक बड़ा सौदा है ।

नीचे दिए गए उदाहरण से मदद मिली:

// call doMyTask1 - here we set state
// then after state is updated...
//     call to doMyTask2 to proceed further in program

constructor(props) {
    // ..

    // This binding is necessary to make `this` work in the callback
    this.doMyTask1 = this.doMyTask1.bind(this);
    this.doMyTask2 = this.doMyTask2.bind(this);
}

function doMyTask1(myparam1) {
    // ..

    this.setState(
        {
            mystate1: 'myvalue1',
            mystate2: 'myvalue2'
            // ...
        },    
        () => {
            this.doMyTask2(myparam1); 
        }
    );
}

function doMyTask2(myparam2) {
    // ..
}

उम्मीद है की वो मदद करदे।

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