क्या प्रतिक्रिया राज्य के अद्यतन के लिए आदेश रखती है?


140

मुझे पता है कि रिएक्ट एसिंक्रोनस रूप से और प्रदर्शन अनुकूलन के लिए बैच में राज्य अपडेट कर सकता है। इसलिए आप कभी भी कॉल करने के बाद अपडेट होने की स्थिति पर भरोसा नहीं कर सकते setState। लेकिन क्या आप राज्य को उसी क्रम में अपडेटsetState करने के लिए रिएक्ट पर भरोसा कर सकते हैं जैसा कि कहा जाता है

  1. एक ही घटक?
  2. विभिन्न घटकों?

निम्नलिखित उदाहरणों में बटन पर क्लिक करने पर विचार करें:

1. क्या कभी इस बात की संभावना है कि असत्य है और ख के लिए सत्य है:

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { a: false, b: false };
  }

  render() {
    return <Button onClick={this.handleClick}/>
  }

  handleClick = () => {
    this.setState({ a: true });
    this.setState({ b: true });
  }
}

2. क्या कभी संभावना है कि एक गलत है और बी के लिए सच है:

class SuperContainer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { a: false };
  }

  render() {
    return <Container setParentState={this.setState.bind(this)}/>
  }
}

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { b: false };
  }

  render() {
    return <Button onClick={this.handleClick}/>
  }

  handleClick = () => {
    this.props.setParentState({ a: true });
    this.setState({ b: true });
  }
}

ध्यान रखें कि ये मेरे उपयोग के मामले के चरम सरलीकरण हैं। मुझे एहसास है कि मैं इसे अलग तरह से कर सकता हूं, उदाहरण के लिए उदाहरण 1 में एक ही समय में दोनों राज्य के पैरामेट्स को अपडेट करना, साथ ही उदाहरण के लिए कॉलबैक में पहले स्टेट अपडेट में दूसरा स्टेटस अपडेट करना 2. हालांकि, यह मेरा सवाल नहीं है, और मैं केवल तभी दिलचस्पी लेता हूं जब एक अच्छी तरह से परिभाषित तरीका होता है जो रिएक्ट इन राज्य अपडेट करता है, और कुछ नहीं।

प्रलेखन द्वारा समर्थित किसी भी उत्तर की बहुत सराहना की जाती है।


1
इसे देखें: stackoverflow.com/a/36087156/3776299
helb

3
यह एक बेतुका सवाल नहीं लगता है, आप यह भी पूछ सकते हैं कि प्रतिक्रिया पृष्ठ के गितुब मुद्दों पर सवाल, दान अब्रामोव आमतौर पर बहुत उपयोगी है। जब मेरे पास इस तरह के पेचीदा सवाल होते तो मैं पूछता और वह जवाब देता। खराब यह है कि इस तरह के मुद्दों को सार्वजनिक रूप से आधिकारिक डॉक्स में साझा नहीं किया जाता है (ताकि अन्य इसे आसानी से एक्सेस कर सकें)। मुझे यह भी लगता है कि रिएक्ट आधिकारिक डॉक्स में आपके प्रश्न से विषय जैसे कुछ विषयों के व्यापक कवरेज का अभाव है,
giorgim

उदाहरण के लिए इसे लें: github.com/facebook/react/issues/11793 , मेरा मानना ​​है कि उस मुद्दे पर चर्चा की गई सामग्री कई डेवलपर्स के लिए उपयोगी होगी, लेकिन यह सामान आधिकारिक डॉक्स पर नहीं है, क्योंकि एफबी लोग इसे उन्नत मानते हैं। संभवतः अन्य चीजों के बारे में है। मुझे लगता है कि एक आधिकारिक लेख, जिसका शीर्षक है, 'राज्य प्रबंधन में गहराई से प्रतिक्रिया' या 'राज्य प्रबंधन के नुकसान' जैसा कुछ शीर्षक, जो आपके प्रश्न की तरह राज्य प्रबंधन के सभी कोने के मामलों का पता नहीं लगाएगा। शायद हम FB डेवलपर्स को इस तरह के सामान के साथ प्रलेखन बढ़ाने के लिए आगे बढ़ा सकते हैं :)
giorgim

मेरे सवाल में मध्यम पर एक महान लेख के लिए एक कड़ी है। इसे 95% राज्य उपयोग के मामलों को कवर करना चाहिए। :)
मीकल

2
@ मिचल लेकिन वह लेख अभी भी इस सवाल का जवाब नहीं देता है IMHO
जियोर्जिम

जवाबों:


336

मैं रिएक्ट पर काम करता हूं।

TLDR:

लेकिन क्या आप राज्य को उसी क्रम में अपडेट करने के लिए रिएक्ट पर भरोसा कर सकते हैं जैसे कि सेटस्टेट के लिए कहा जाता है

  • एक ही घटक?

हाँ।

  • विभिन्न घटकों?

हाँ।

आदेश अद्यतन की हमेशा सम्मान दिया जाता है। चाहे आप उन्हें "के बीच" एक मध्यवर्ती स्थिति देखते हैं या नहीं यह इस बात पर निर्भर करता है कि आप बैच में हैं या नहीं।

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

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


इसे समझने की कुंजी यह है कि कोई भी बात नहीं है कि एक रिएक्ट इवेंट हैंडलर के अंदरsetState() आप कितने घटकों को कॉल करते हैं , वे इवेंट के अंत में केवल एक ही रेंडर प्रस्तुत करेंगे । यह बड़े अनुप्रयोगों में अच्छे प्रदर्शन के लिए महत्वपूर्ण है क्योंकि अगर Childऔर Parentप्रत्येक setState()जब एक क्लिक इवेंट को संभालते हैं, तो आप Childदो बार फिर से प्रस्तुत नहीं करना चाहते हैं ।

आपके दोनों उदाहरणों में, setState()कॉल एक प्रतिक्रिया घटना हैंडलर के अंदर होती है। इसलिए वे हमेशा घटना के अंत में एक साथ बह जाते हैं (और आप मध्यवर्ती स्थिति नहीं देखते हैं)।

अद्यतन हमेशा उथले रूप से विलय के क्रम में होते हैं । तो अगर पहला अपडेट है {a: 10}, दूसरा है {b: 20}, और तीसरा है {a: 30}, गाया हुआ राज्य होगा {a: 30, b: 20}। एक ही राज्य कुंजी के लिए हाल ही में अद्यतन (जैसे aमेरे उदाहरण में) हमेशा "जीतता है"।

this.stateवस्तु अद्यतन किया जाता है जब हम बैच के अंत में यूआई को फिर से प्रस्तुत करना। इसलिए यदि आपको पिछली स्थिति के आधार पर स्थिति को अपडेट करने की आवश्यकता है (जैसे कि एक काउंटर बढ़ाना), तो आपको उस कार्यात्मक setState(fn)संस्करण का उपयोग करना चाहिए जो आपको पढ़ने के बजाय पिछले राज्य को देता है this.state। यदि आप इसके लिए तर्क के बारे में उत्सुक हैं, तो मैंने इसे इस टिप्पणी में गहराई से समझाया ।


आपके उदाहरण में, हम "मध्यवर्ती स्थिति" नहीं देखेंगे क्योंकि हम एक रिएक्ट इवेंट हैंडलर के अंदर हैं जहाँ बैचिंग सक्षम है (क्योंकि रिएक्ट "जानता है" जब हम उस इवेंट से बाहर निकल रहे हैं)।

हालाँकि, रिएक्ट 16 और पुराने दोनों संस्करणों में, रिएक्ट इवेंट हैंडलर्स के बाहर डिफ़ॉल्ट रूप से कोई बैचिंग नहीं है । इसलिए यदि आपके उदाहरण में हमारे पास AJAX प्रतिक्रिया हैंडलर था handleClick, तो प्रत्येक setState()को तुरंत संसाधित किया जाएगा जैसा कि ऐसा होता है। इस मामले में, हां, आपको एक मध्यवर्ती स्थिति दिखाई देगी :

promise.then(() => {
  // We're not in an event handler, so these are flushed separately.
  this.setState({a: true}); // Re-renders with {a: true, b: false }
  this.setState({b: true}); // Re-renders with {a: true, b: true }
  this.props.setParentState(); // Re-renders the parent
});

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

promise.then(() => {
  // Forces batching
  ReactDOM.unstable_batchedUpdates(() => {
    this.setState({a: true}); // Doesn't re-render yet
    this.setState({b: true}); // Doesn't re-render yet
    this.props.setParentState(); // Doesn't re-render yet
  });
  // When we exit unstable_batchedUpdates, re-renders once
});

आंतरिक रूप से प्रतिक्रिया घटना संचालकों को लपेटा जा रहा unstable_batchedUpdatesहै, इसीलिए वे डिफ़ॉल्ट रूप से बैचेन हैं। ध्यान दें कि अपडेट को unstable_batchedUpdatesदो बार लपेटने का कोई प्रभाव नहीं पड़ता है। जब हम सबसे बाहरी unstable_batchedUpdatesकॉल से बाहर निकलते हैं, तो अपडेट फ्लश हो जाते हैं ।

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


योग करने के लिए, यह एक भ्रमित करने वाला विषय है क्योंकि रिएक्ट केवल डिफ़ॉल्ट रूप से ईवेंट हैंडलर के अंदर बैचते हैं। यह भविष्य के संस्करणों में बदल जाएगा, और व्यवहार तब अधिक सीधा होगा। लेकिन समाधान कम बैच के लिए नहीं है , यह डिफ़ॉल्ट रूप से अधिक बैच करने के लिए है । यही हम करने जा रहे हैं।


1
"हमेशा आदेश सही पाने" का एक तरीका एक अस्थायी वस्तु बनाना है, विभिन्न मूल्यों (जैसे obj.a = true; obj.b = true) को असाइन करें और फिर अंत में बस करें this.setState(obj)। यह सुरक्षित है, भले ही आप किसी इवेंट हैंडलर के अंदर हों या नहीं। यदि आप अक्सर अपने आप को घटना संचालकों के बाहर कई बार राज्य स्थापित करने की गलती करते हुए पाते हैं, तो यह एक गलत चाल हो सकती है।
क्रिस

इसलिए हम वास्तव में केवल एक ईवेंट हैंडलर तक सीमित होने के लिए बैचिंग पर भरोसा नहीं कर सकते हैं - जैसा कि आपने स्पष्ट किया है, कम से कम क्योंकि यह जल्द ही मामला नहीं होगा। फिर हम सबसे हाल ही में राज्य तक पहुँच प्राप्त करने के लिए updater फंक्शन के साथ setState का उपयोग करने वाले हैं, है ना? लेकिन क्या होगा अगर मुझे कुछ डेटा पढ़ने के लिए एक एक्सएचआर बनाने के लिए कुछ राज्य का उपयोग करना होगा। ऐसा लगता है कि मुझे अपडाउन करने वाले को कॉलबैक (और इसलिए साइड इफेक्ट) के साथ एक्सएचआर डालना होगा। क्या यह सबसे अच्छा अभ्यास माना जाता है, फिर?
मक्सिम गुमेरोव

1
और वैसे भी इसका मतलब है कि हमें इस से नहीं पढ़ना चाहिए। कुछ तर्क पढ़ने के लिए एकमात्र उचित तरीका है। इसके तर्क से, इसे अपडेटर फ़ंक्शन में पढ़ना है। और, यह लिखना .state भी असुरक्षित है। तो फिर इस तक पहुँचने की अनुमति क्यों दें। उन लोगों को शायद स्टैंडअलोन सवाल करना चाहिए, लेकिन ज्यादातर मैं सिर्फ यह समझने की कोशिश कर रहा हूं कि क्या मुझे स्पष्टीकरण सही मिला।
मक्सिम गुमेरोव

10
इस उत्तर को reactjs.org प्रलेखन में जोड़ा जाना चाहिए
दीन जॉन

2
क्या आप इस पोस्ट को स्पष्ट कर सकते हैं यदि "रिएक्ट इवेंट हैंडलर" में शामिल हैं componentDidUpdateऔर रिएक्ट 16 के रूप में अन्य जीवनचक्र कॉलबैक शामिल हैं ? अग्रिम में धन्यवाद!
इवान

6

यह वास्तव में एक काफी दिलचस्प सवाल है, लेकिन जवाब बहुत जटिल नहीं होना चाहिए। माध्यम पर यह महान लेख है जिसका उत्तर है।

1) यदि आप ऐसा करते हैं

this.setState({ a: true });
this.setState({ b: true });

मुझे नहीं लगता कि कोई ऐसी स्थिति aहोगी जहां बैचिंग के कारण होगा trueऔर bहोगा ।false

हालाँकि, अगर bयह निर्भर हैa तो वास्तव में ऐसी स्थिति हो सकती है जहाँ आपको अपेक्षित राज्य नहीं मिलेगा।

// assuming this.state = { value: 0 };
this.setState({ value: this.state.value + 1});
this.setState({ value: this.state.value + 1});
this.setState({ value: this.state.value + 1});

उपरोक्त सभी कॉल संसाधित this.state.valueहोने के बाद 1 होगी, न कि 3 जैसी आपको उम्मीद होगी।

यह लेख में उल्लेख किया गया है: setState accepts a function as its parameter

// assuming this.state = { value: 0 };
this.setState((state) => ({ value: state.value + 1}));
this.setState((state) => ({ value: state.value + 1}));
this.setState((state) => ({ value: state.value + 1}));

यह हमें देगा this.state.value === 3


क्या होगा अगर this.state.valueईवेंट हैंडलर्स (जहां दोनों में अद्यतन किया जाता है setState(जहां batched है) और AJAX कॉलबैक setStateहै नहीं batched)। ईवेंट हैंडलर में मैं updater functionहमेशा यह सुनिश्चित करता हूं कि मैं फ़ंक्शन द्वारा प्रदान की गई वर्तमान स्थिति को अपडेट करके स्टेट को अपडेट कर दूं। क्या मुझे setStateAJAX कॉलबैक के कोड के अंदर एक updater फ़ंक्शन के साथ उपयोग करना चाहिए, भले ही मुझे पता हो कि यह बैच नहीं है? आप setStateएक AJAX कॉलबैक के साथ या एक updater फ़ंक्शन का उपयोग किए बिना स्पष्ट कर सकते हैं ? धन्यवाद!
टोनिक्स

@ मिचल, हाय मिशल सिर्फ सवाल पूछना चाहते थे, क्या यह सच है कि अगर हमारे पास यह है ।सेट्स ({मूल्य: 0}); it.setState ({मान: this.state.value + 1}); पहले सेटस्टेट को नजरअंदाज किया जाएगा और केवल दूसरे सेटस्टैट को ही अंजाम दिया जाएगा?
डिकेंस

@ मुझे लगता है कि दोनों setStateको मार दिया जाएगा, लेकिन आखिरी जीत होगी।
मीकल

3

एक ही चक्र के दौरान कई कॉल एक साथ बैच हो सकते हैं। उदाहरण के लिए, यदि आप एक ही चक्र में एक से अधिक बार किसी वस्तु की मात्रा बढ़ाने का प्रयास करते हैं, तो इसका परिणाम निम्न होगा:

Object.assign(
  previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ...
)

https://reactjs.org/docs/react-component.html


3

डॉक्टर के रूप में

setState () enqueues घटक राज्य में परिवर्तन और प्रतिक्रिया है कि इस घटक और उसके बच्चों को फिर से गाया अद्यतन स्थिति के साथ होने की जरूरत बताता है। यह वह प्राथमिक विधि है जिसका उपयोग आप ईवेंट हैंडलर और सर्वर प्रतिक्रियाओं के जवाब में यूजर इंटरफेस को अपडेट करने के लिए करते हैं।

यह परिवर्तन को कतार में बदल देगा ( FIFO : First In First Out) पहला कॉल पहले प्रीफॉर्म होगा


हाय अली, सिर्फ सवाल पूछना चाहता था, क्या यह सच है कि अगर हमारे पास यह है (स्ट्रेट (मान: 0})); it.setState ({मान: this.state.value + 1}); पहले सेटस्टेट को नजरअंदाज किया जाएगा और केवल दूसरे सेटस्टैट को ही अंजाम दिया जाएगा?
डिकेन्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.