रीप्स फॉर्म में प्रॉप्स पर अद्यतन स्थिति बदल रही है


184

मुझे एक रिएक्ट फॉर्म और राज्य को ठीक से प्रबंधित करने में परेशानी हो रही है। मेरे पास एक फॉर्म (एक मोडल) में एक समय इनपुट फ़ील्ड है। प्रारंभिक मान को राज्य चर के रूप में सेट किया जाता है getInitialState, और इसे मूल घटक से पास किया जाता है। यह अपने आप में ठीक काम करता है।

समस्या तब आती है जब मैं मूल घटक के माध्यम से डिफ़ॉल्ट start_time मान को अपडेट करना चाहता हूं। अद्यतन स्वयं मूल घटक में होता है setState start_time: new_time। हालाँकि मेरे रूप में, डिफ़ॉल्ट start_time मान कभी नहीं बदलता है, क्योंकि यह केवल एक बार में परिभाषित किया गया है getInitialState

मैंने componentWillUpdateराज्य में एक परिवर्तन को लागू करने के लिए उपयोग करने की कोशिश की है setState start_time: next_props.start_time, जो वास्तव में काम करता था, लेकिन मुझे Uncaught RangeError: Maximum call stack size exceededत्रुटियां दीं ।

तो मेरा सवाल यह है कि इस मामले में राज्य को अपडेट करने का सही तरीका क्या है? क्या मैं किसी तरह इस गलत के बारे में सोच रहा हूं?

वर्तमान कोड:

@ModalBody = React.createClass
  getInitialState: ->
    start_time: @props.start_time.format("HH:mm")

  #works but takes long and causes:
  #"Uncaught RangeError: Maximum call stack size exceeded"
  componentWillUpdate: (next_props, next_state) ->
    @setState(start_time: next_props.start_time.format("HH:mm"))

  fieldChanged: (fieldName, event) ->
    stateUpdate = {}
    stateUpdate[fieldName] = event.target.value
    @setState(stateUpdate)

  render: ->
    React.DOM.div
      className: "modal-body"
      React.DOM.form null,
        React.createElement FormLabelInputField,
          type: "time"
          id: "start_time"
          label_name: "Start Time"
          value: @state.start_time
          onChange: @fieldChanged.bind(null, "start_time”)

@FormLabelInputField = React.createClass
  render: ->
    React.DOM.div
      className: "form-group"
      React.DOM.label
        htmlFor: @props.id
        @props.label_name + ": "
      React.DOM.input
        className: "form-control"
        type: @props.type
        id: @props.id
        value: @props.value
        onChange: @props.onChange

जवाबों:


287

घटकWillReceiveProps को 16 प्रतिक्रिया के बाद से हटा दिया जाता है : इसके बजाय getDerivedStateFromProps का उपयोग करें

अगर मैं सही तरीके से समझूं, तो आपके पास एक मूल घटक है जो गुजर रहा है start_time करने के लिए नीचे ModalBodyघटक है जो यह अपने आप ही राज्य को आवंटित? और आप उस समय को माता-पिता से अपडेट करना चाहते हैं, न कि बच्चे के घटक के रूप में।

इस परिदृश्य से निपटने के लिए रिएक्ट के कुछ सुझाव हैं। (ध्यान दें, यह एक पुराना लेख है, जिसे तब से वेब से हटा दिया गया है। यहाँ घटक प्रॉप्स पर वर्तमान डॉक का लिंक दिया गया है )।

getInitialStateअक्सर राज्य उत्पन्न करने के लिए प्रॉप्स का उपयोग करने से "सत्य के स्रोत" का दोहराव होता है, अर्थात जहां वास्तविक डेटा है। यह है क्योंकिgetInitialState घटक पहली बार बनाए जाने पर केवल इनवॉइस किया जाता है।

जब भी संभव हो, यह सुनिश्चित करने के लिए कि वे बाद में सिंक से बाहर नहीं निकलते हैं और रखरखाव में परेशानी पैदा करते हैं, पर मूल्यों की गणना करें।

मूल रूप से, जब भी आप माता-पिता propsको एक बच्चे को सौंपते हैं, तो stateरेंडर करने का तरीका हमेशा प्रोप अपडेट पर नहीं कहा जाता है। आपको componentWillReceivePropsविधि का उपयोग करके इसे मैन्युअल रूप से आह्वान करना होगा ।

componentWillReceiveProps(nextProps) {
  // You don't have to do this check first, but it can help prevent an unneeded render
  if (nextProps.startTime !== this.state.startTime) {
    this.setState({ startTime: nextProps.startTime });
  }
}


7
@ दोस्त यह अभी तक पदावनत नहीं किया गया है, आप जो उल्लेख करते हैं वह भविष्य के संदर्भ के लिए सिर्फ एक प्रमुख है। मैं बोली[..]going to be deprecated in the future
गद्दी

7
@poepje यह अभी तक नहीं निकाला जा सकता है, लेकिन इसे वर्तमान मानक द्वारा असुरक्षित के रूप में देखा जाता है और संभवतः इसे टाला जाना चाहिए
अनफ्लो

12
तो, घटक के बाद यह करने का नया तरीका क्या होना चाहिए?
बोरिस डी। तेहरोव

5
@ बोरिस अब प्रतिक्रिया टीम मूल रूप से आपको भरवां होने के लिए कह रही है। वे आपको एक नया तरीका देते हैं, जिसे getDerivedStateFromProps कहा जाता है। पकड़ यह है कि यह एक स्थिर विधि है। मतलब आप राज्य को अद्यतन करने के लिए अतुल्यकालिक कुछ भी नहीं कर सकते हैं (क्योंकि आपको तुरंत नया राज्य लौटना होगा), न तो आप कक्षा के तरीकों या खेतों तक पहुँच सकते हैं। आप संस्मरण का उपयोग भी कर सकते हैं, लेकिन यह हर उपयोग के मामले में फिट नहीं है। एक बार फिर, प्रतिक्रिया टीम चीजों को करने के अपने तरीके को मजबूर करना चाहती है। यह एक बहुत ही बेवकूफ और अक्षम डिजाइन निर्णय है।
ig-dev

76

जाहिर तौर पर चीजें बदल रही हैं ...। getDerivedStateFromProps () अब पसंदीदा कार्य है।

class Component extends React.Component {
  static getDerivedStateFromProps(props, current_state) {
    if (current_state.value !== props.value) {
      return {
        value: props.value,
        computed_prop: heavy_computation(props.value)
      }
    }
    return null
  }
}

(उपरोक्त कोड danburzo @ github द्वारा)


7
FYI करें, आपको यह भी वापस करने की आवश्यकता है nullकि अगर आपके अधिकार के बाद कुछ भी नहीं बदलना चाहिए, तो आपको साथ जाना चाहिएreturn null
Ilgıt Yıldırım

@ IlgıtYıldırım - ने कोड संपादित किया है क्योंकि 4 लोगों ने आपकी टिप्पणी को गलत ठहराया है - क्या इससे वास्तव में फर्क पड़ता है?
ErichBSchulz

एक बहुत अच्छा संसाधन है जो विभिन्न विकल्पों पर गहराई से जाता है और आप getDerivedStateFromPropsया तो या ज्ञापन का उपयोग क्यों करेंगे ।jj.org.org
blog/

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

39

componentWillReceiveProps क्योंकि इसे "अक्सर बग और असंगतियों की ओर जाता है" का उपयोग किया जा रहा है।

यदि बाहर से कुछ बदलता है, तो बच्चे के घटक को पूरी तरह से रीसेट करने पर विचार करेंkey

keyचाइल्ड कंपोनेंट को एक प्रॉप प्रदान करने से यह सुनिश्चित हो जाता है कि जब भी keyबाहर से परिवर्तन का मूल्य हो , तो यह कंपोनेंट पुनः प्रदान किया जाता है। उदाहरण के लिए,

<EmailInput
  defaultEmail={this.props.user.email}
  key={this.props.user.id}
/>

इसके प्रदर्शन पर:

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


1
कुंजी, रहस्य! जैसा कि ऊपर वर्णित रिएक्ट 16 में पूरी तरह से काम करता है
डैरेन स्वीनी

कुंजी काम नहीं करेगी, अगर यह एक वस्तु है और आपके पास एक अद्वितीय स्ट्रिंग नहीं है
user3468806

कुंजी वस्तुओं के लिए काम करती है, मैंने इसे किया। बेशक मैं कुंजी के लिए एक अद्वितीय स्ट्रिंग था।
tsujp

@ user3468806 यदि यह बाहरी संदर्भ के साथ एक जटिल वस्तु नहीं है, तो आप JSON.stringify(myObject)अपनी वस्तु से एक अद्वितीय कुंजी प्राप्त करने के लिए उपयोग कर सकते हैं ।
रॉय

24

इसमें कंपोनेंटड्यूपडेट भी उपलब्ध है।

कार्य

componentDidUpdate(prevProps, prevState, snapshot)

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

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


मैं अंत का उपयोग कर रहा हूं componentDidUpdateक्योंकि यह सरल है और यह अधिकांश मामलों के लिए अधिक उपयुक्त है।
कीटलडॉग

14

ऐसा करने का नया हुक तरीका घटक का उपयोग करने के लिए है।

componentWillReceiveProps(nextProps) {
  // You don't have to do this check first, but it can help prevent an unneeded render
  if (nextProps.startTime !== this.state.startTime) {
    this.setState({ startTime: nextProps.startTime });
  }
}

एक कार्यात्मक हुक चालित घटक में निम्नलिखित बन जाता है:

// store the startTime prop in local state
const [startTime, setStartTime] = useState(props.startTime)
// 
useEffect(() => {
  if (props.startTime !== startTime) {
    setStartTime(props.startTime);
  }
}, [props.startTime]);

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


5

आप शायद राज्य की आवश्यकता नहीं है

1. माता-पिता से एक कुंजी सेट करें

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

2. getDerivedStateFromProps/componentWillReceiveProps

यदि कुंजी किसी कारण से काम नहीं करती है (शायद घटक शुरू करने के लिए बहुत महंगा है)

उपयोग करके getDerivedStateFromPropsआप राज्य के किसी भी हिस्से को रीसेट कर सकते हैं लेकिन यह इस समय (v16.7) थोड़ी छोटी गाड़ी लगती है!, उपयोग के लिए लिंक देखें!


2

प्रतिक्रिया प्रलेखन से: https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html

जब प्रॉप्स परिवर्तन एक विरोधी प्रतिमान है, तो मिटा राज्य

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

  1. पूरी तरह से घटक नियंत्रित: ParentComponentके ModalBodyस्वामी होगा start_timeराज्य। यह इस मामले में मेरा पसंदीदा तरीका नहीं है क्योंकि मुझे लगता है कि मोडल को इस राज्य का मालिक होना चाहिए।
  2. एक कुंजी के साथ पूरी तरह से अनियंत्रित घटक: यह मेरा पसंदीदा तरीका है। प्रतिक्रिया प्रलेखन से एक उदाहरण: https://codesandbox.io/s/6v1znlxyxn । आप अपने आप से पूरी तरह से start_timeराज्य ModalBodyका उपयोग करेंगे और getInitialStateवैसे ही उपयोग करेंगे जैसे आप पहले ही कर चुके हैं। स्थिति को रीसेट करने के लिए start_time, आप बस से कुंजी को बदलते हैंParentComponent


0

मेमोइज़ का उपयोग करें

राज्य की ओप की व्युत्पत्ति प्रॉप्स का प्रत्यक्ष हेरफेर है, जिसमें किसी भी वास्तविक व्युत्पत्ति की आवश्यकता नहीं होती है। दूसरे शब्दों में, यदि आपके पास एक प्रोप है जिसे सीधे उपयोग या रूपांतरित किया जा सकता है, तो राज्य पर प्रोप को स्टोर करने की कोई आवश्यकता नहीं है

यह देखते हुए कि राज्य का मूल्य start_timeकेवल प्रोप है start_time.format("HH:mm"), घटक को अपडेट करने के लिए प्रोप में निहित जानकारी पहले से ही पर्याप्त है।

हालाँकि यदि आप किसी प्रोपर बदलाव पर केवल फॉर्मेट को कॉल करना चाहते हैं, तो इस नवीनतम दस्तावेज़ के अनुसार करने का सही तरीका मेमोइज़ के माध्यम से होगा: https://reactjs.org/blog/2018/06/07/you-probably-dont- जरूरत व्युत्पन्न-state.html # क्या-के बारे में-Memoization


-1

मुझे लगता है कि उपयोग रेफरी मेरे लिए सुरक्षित है, न ही ऊपर दिए गए किसी तरीके की देखभाल की आवश्यकता है।

class Company extends XComponent {
    constructor(props) {
        super(props);
        this.data = {};
    }
    fetchData(data) {
        this.resetState(data);
    }
    render() {
        return (
            <Input ref={c => this.data['name'] = c} type="text" className="form-control" />
        );
    }
}
class XComponent extends Component {
    resetState(obj) {
        for (var property in obj) {
            if (obj.hasOwnProperty(property) && typeof this.data[property] !== 'undefined') {
                if ( obj[property] !== this.data[property].state.value )
                    this.data[property].setState({value: obj[property]});
                else continue;
            }
            continue;
        }
    }
}

मुझे लगता है कि यह प्रतिक्रिया गूढ़ है (कोड शायद ही पठनीय है और बिना किसी स्पष्टीकरण के / ओपी की समस्या से जुड़े) और ओपी की समस्या से नहीं निपटता है, जो कि प्रारंभिक स्थिति को कैसे संभालना है।
netchkin
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.