ReactJS राज्य बनाम सहारा


121

यह जवाबदेह और राय के बीच उस लाइन को फैलाने वाला हो सकता है, लेकिन मैं आगे और पीछे जा रहा हूं कि कैसे रिएक्टजेएस घटक को संरचना करना है क्योंकि जटिलता बढ़ती है और कुछ दिशा का उपयोग कर सकती है।

AngularJS से आने वाले, मैं अपने मॉडल को एक संपत्ति के रूप में घटक में पास करना चाहता हूं और घटक को सीधे मॉडल को संशोधित करना है। या क्या मुझे मॉडल को विभिन्न stateगुणों में विभाजित करना चाहिए और वापस ऊपर भेजते समय इसे एक साथ संकलित करना चाहिए? ReactJS तरीका क्या है?

एक ब्लॉग पोस्ट संपादक का उदाहरण लें। मॉडल को सीधे संशोधित करने की कोशिश कर रहा है:

var PostEditor = React.createClass({
  updateText: function(e) {
    var text = e.target.value;
    this.props.post.text = text;
    this.forceUpdate();
  },
  render: function() {
    return (
      <input value={this.props.post.text} onChange={this.updateText}/>
      <button onClick={this.props.post.save}/>Save</button>
    );
  }
});

जो गलत लगता है।

क्या यह हमारी textमॉडल संपत्ति बनाने के लिए और अधिक प्रतिक्रियाशील तरीका है state, और इसे सहेजने से पहले मॉडल में वापस संकलित करें:

var PostEditor = React.createClass({
  getInitialState: function() {
    return {
      text: ""
    };
  },
  componentWillMount: function() {
    this.setState({
      text: this.props.post.text
    });
  },
  updateText: function(e) {
    this.setState({
      text: e.target.value
    });
  },
  savePost: function() {
    this.props.post.text = this.state.text;
    this.props.post.save();
  },
  render: function() {
    return (
      <input value={this.state.text} onChange={this.updateText}/>
      <button onClick={this.savePost}/>Save</button>
    );
  }
});

इसके लिए कॉल की आवश्यकता नहीं है this.forceUpdate(), लेकिन जैसे-जैसे मॉडल बढ़ता है, (एक पोस्ट में लेखक, विषय, टैग, टिप्पणियां, रेटिंग आदि हो सकते हैं ...) घटक वास्तव में जटिल होने लगता है।

जाने के लिए ReactLink के साथ पहली विधि है ?

जवाबों:


64

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

आप उन कॉलबैक को पास कर सकते हैं, जिन्हें आपके डेटा को संशोधित करने की आवश्यकता है, और उन्हें चाइल्ड कंपोनेंट से कॉल करें।

इसे संशोधित करना। सीधे तौर पर या इसके लिए। यह एक अच्छा विचार नहीं है, क्योंकि रिएक्ट परिवर्तनों को लेने में सक्षम नहीं होगा। ऐसा इसलिए है क्योंकि रिएक्ट आपके पोस्ट प्रोप के उथले तुलना को निर्धारित करता है कि क्या यह बदल गया है।

मैं इस बनाया jsfiddle कैसे डेटा एक बाहरी से एक आंतरिक घटक के प्रवाह सकता है दिखाने के लिए।

handleClickविधि शो (आईएम) ठीक से अद्यतन राज्य के लिए 3 तरीके:

var Outer = React.createClass({

  getInitialState: function() {
    return {data: {value: 'at first, it works'}};
  },

  handleClick: function () {

    // 1. This doesn't work, render is not triggered.
    // Never set state directly because the updated values
    // can still be read, which can lead to unexpected behavior.

    this.state.data.value = 'but React will never know!';

    // 2. This works, because we use setState

    var newData = {value: 'it works 2'};
    this.setState({data: newData});

    // 3. Alternatively you can use React's immutability helpers
    // to update more complex models.
    // Read more: http://facebook.github.io/react/docs/update.html

    var newState = React.addons.update(this.state, {
      data: {value: {$set: 'it works'}}
    });
    this.setState(newState);
 },

  render: function() {
      return <Inner data={this.state.data} handleClick={this.handleClick} />;
  }
});

लेकिन हम क्या करते हैं यदि हमारे पास एक अपारदर्शी मॉडल है, जिसके अपने राज्य में हेरफेर कार्य हैं? उदाहरण के लिए, मान लीजिए कि एक textक्षेत्र के बजाय , हमारे पास एक setText विधि है जो सत्यापन और कुछ अन्य सामान करती है। मैं विधि (2) को देख सकता हूं यदि setTextशुद्ध है और मॉडल का एक नया उदाहरण देता है। हालांकि, अगर setTextसिर्फ आंतरिक स्थिति को अपडेट करें तो हमें कॉल करने की आवश्यकता होगी forceUpdate, है ना?
हुगोमैग

1
हां, आप कॉल कर सकते हैं forceUpdate, लेकिन उस बिंदु पर आप रिएक्ट से बाहर "लीक" कर रहे हैं। setState()मैन्युअल रूप से पुन: रेंडर करने से बचने के लिए अपारदर्शी मॉडल को कॉलबैक पास करना बेहतर हो सकता है ।
jxg

मुझे अभी भी यकीन नहीं है कि मैं पूरी तरह से समझ रहा हूँ। तो डेटा को संशोधित करने के लिए किए गए किसी भी घटक को पास किए गए प्रॉपर की एक गहरी प्रतिलिपि करने की आवश्यकता है? फिर संशोधित करें और उस प्रति को ऊपर की ओर भेजें ताकि मूल डेटा को संशोधित न किया जा सके? आखिरकार परिवर्तन रूट के लिए सभी तरह से बह जाएगा, जहां यह निपटा है, और पूरे ऐप को फिर से प्रस्तुत किया गया है? क्या वह सही है?
निकोलस 19

97

2016 को अपडेट करना: प्रतिक्रिया बदल गई है, और स्पष्टीकरण "प्रॉप्स बनाम राज्य" बहुत सरल हो गया। यदि किसी घटक को डेटा बदलने की आवश्यकता है - इसे एक स्थिति में डालें, अन्यथा प्रॉप्स में। क्योंकि प्रॉप्स अब केवल पढ़े जाते हैं।

सहारा और राज्य के बीच सटीक अंतर क्या है?

आप यहाँ अच्छी व्याख्या पा सकते हैं (पूर्ण संस्करण)

रंगमंच की सामग्री और स्थिति को बदलना


1
वास्तव में सेटप्रॉप्स () एक घटक के अंदर प्रॉप्स को बदल सकते हैं और एक पुन: रेंडर को ट्रिगर कर सकते हैं
WaiKit Kung

2
setPropsवंचित है और इसका उपयोग नहीं किया जाना चाहिए। प्रतिस्थापन घटक को फिर से प्रस्तुत करना है और प्रतिक्रिया को मतभेदों को संभालने देना है।
jdmichal

और यदि आप एक व्याख्याकार वीडियो की तलाश कर रहे हैं: youtube.com/watch?v=qh3dYM6Keuw
jaisonDavis

35

रिएक्ट डॉक से

प्रॉप्स अपरिवर्तनीय हैं: वे माता-पिता से पारित हो जाते हैं और माता-पिता के "स्वामित्व" में होते हैं। परस्पर क्रियाओं को कार्यान्वित करने के लिए, हम घटक में परस्पर अवस्था का परिचय देते हैं। इस .state घटक के लिए निजी है और इस .setState () को कॉल करके बदला जा सकता है। जब स्थिति को अद्यतन किया जाता है, तो घटक स्वयं को पुन: प्रस्तुत करता है।

से TrySpace : जब रंगमंच की सामग्री (या राज्य) अपडेट किया जाता है (setProps / setState या माता-पिता के माध्यम से) घटक के रूप में अच्छी तरह से फिर से बना देता है।


16

प्रतिक्रिया में सोच से एक पढ़ने :

आइए प्रत्येक के माध्यम से जाने और यह पता लगाएं कि कौन सा राज्य है। डेटा के प्रत्येक टुकड़े के बारे में तीन प्रश्न पूछें:

  1. यह एक माता पिता से सहारा के माध्यम से पारित किया है? यदि ऐसा है, तो यह संभवतः नहीं है।
  2. क्या यह समय के साथ बदलता है? यदि नहीं, तो यह संभवतः नहीं है।

  3. क्या आप अपने घटक में किसी अन्य राज्य या प्रॉप्स के आधार पर इसकी गणना कर सकते हैं? यदि हां, तो यह राज्य नहीं है।


13

मुझे यकीन नहीं है कि अगर मैं आपके सवाल का जवाब दे रहा हूं, लेकिन मैंने पाया है कि विशेष रूप से एक बड़े / बढ़ते आवेदन में, कंटेनर / घटक पैटर्न अविश्वसनीय रूप से अच्छी तरह से है।

अनिवार्य रूप से आपके पास दो रिएक्ट घटक हैं:

  • एक "शुद्ध" प्रदर्शन घटक, जो स्टाइल और डोम इंटरैक्शन से संबंधित है;
  • एक कंटेनर घटक, जो बाहरी डेटा तक पहुंचने / बचत करने, राज्य का प्रबंधन करने और प्रदर्शन घटक प्रदान करने से संबंधित है।

उदाहरण

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

/**
 * Container Component
 *
 *  - Manages component state
 *  - Does plumbing of data fetching/saving
 */

var PostEditorContainer = React.createClass({
  getInitialState: function() {
    return {
      text: ""
    };
  },

  componentWillMount: function() {
    this.setState({
      text: getPostText()
    });
  },

  updateText: function(text) {
    this.setState({
      text: text
    });
  },

  savePost: function() {
    savePostText(this.state.text);
  },

  render: function() {
    return (
      <PostEditor
        text={this.state.text}
        onChange={this.updateText.bind(this)}
        onSave={this.savePost.bind(this)}
      />
    );
  }
});


/**
 * Pure Display Component
 *
 *  - Calculates styling based on passed properties
 *  - Often just a render method
 *  - Uses methods passed in from container to announce changes
 */

var PostEditor = React.createClass({
  render: function() {
    return (
      <div>
        <input type="text" value={this.props.text} onChange={this.props.onChange} />
        <button type="button" onClick={this.props.onSave} />
      </div>
    );
  }
});

लाभ

प्रदर्शन तर्क और डेटा / राज्य प्रबंधन को अलग रखकर, आपके पास एक पुन: प्रयोज्य प्रदर्शन घटक है जो:

  • आसानी से प्रतिक्रिया-घटक-खेल के मैदान की तरह कुछ का उपयोग कर सहारा के विभिन्न सेटों के साथ पुनरावृत्त किया जा सकता है
  • विभिन्न व्यवहार के लिए एक अलग कंटेनर के साथ लिपटे जा सकते हैं (या अपने आवेदन के बड़े हिस्से के निर्माण के लिए अन्य घटकों के साथ गठबंधन कर सकते हैं

आपके पास एक कंटेनर घटक भी है जो सभी बाहरी संचार से संबंधित है। यदि आप अपने डेटा को एक्सेस करने के तरीके के बारे में लचीला होना आसान बनाते हैं यदि आप बाद में * कोई गंभीर बदलाव करते हैं।

यह पैटर्न लेखन और इकाई परीक्षणों को लागू करने को और अधिक सरल बनाता है।

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

* फ्लक्स पैटर्न पर पढ़ें, और मार्टी.जेएस पर एक नज़र डालें , जो काफी हद तक इस जवाब को प्रेरित करता है (और मैं हाल ही में बहुत उपयोग कर रहा हूं) Redux (और रिएक्शन-रेडक्स ), जो इस पैटर्न को बहुत अच्छी तरह से लागू करते हैं।

2018 या बाद में इसे पढ़ने वालों के लिए ध्यान दें:

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


0

मुझे लगता है कि आप एक एंटी-पैटर्न का उपयोग कर रहे हैं जिसे फेसबुक ने पहले ही इस लिंक पर समझाया है

यहां वह चीज है जो आप पा रहे हैं:

React.createClass({
  getInitialState: function() {
    return { value: { foo: 'bar' } };
  },

  onClick: function() {
    var value = this.state.value;
    value.foo += 'bar'; // ANTI-PATTERN!
    this.setState({ value: value });
  },

  render: function() {
    return (
      <div>
        <InnerComponent value={this.state.value} />
        <a onClick={this.onClick}>Click me</a>
      </div>
    );
  }
});

पहली बार आंतरिक घटक प्रदान किया जाता है, इसमें वैल्यू प्रोप के रूप में {foo: 'bar'} होगा। यदि उपयोगकर्ता लंगर पर क्लिक करता है, तो मूल घटक की स्थिति {मान: {foo: 'barbar'}} को अपडेट हो जाएगी, जिससे आंतरिक घटक की पुन: रेंडरिंग प्रक्रिया शुरू हो जाएगी, जो {foo: 'barbar' के रूप में प्राप्त होगी} प्रोप के लिए नया मूल्य।

समस्या यह है कि चूंकि माता-पिता और आंतरिक घटक एक ही ऑब्जेक्ट के संदर्भ को साझा करते हैं, जब ऑब्जेक्ट ऑनक्लिक फ़ंक्शन के लाइन 2 पर उत्परिवर्तित हो जाता है, तो आंतरिक घटक का प्रोप बदल जाएगा। तो, जब पुन: प्रतिपादन की प्रक्रिया शुरू होती है, और shouldComponentUpdate मंगाई जाती है, तो यह .props.value.foo अगले next के समान होगा।

नतीजतन, जब से हम प्रोप और शॉर्ट सर्किट को फिर से रेंडर करने की प्रक्रिया में बदलाव को याद करेंगे, यूआई 'बार' से 'बारबार' में अपडेट नहीं होगा


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