प्रतिक्रिया में नेस्टेड राज्य गुणों को कैसे अपडेट करें


389

मैं इस तरह से नेस्टेड संपत्ति का उपयोग करके अपने राज्य को व्यवस्थित करने की कोशिश कर रहा हूं:

this.state = {
   someProperty: {
      flag:true
   }
}

लेकिन इस तरह अद्यतन राज्य,

this.setState({ someProperty.flag: false });

काम नहीं करता है। इसे सही तरीके से कैसे किया जा सकता है?


4
तुम्हारा क्या मतलब है काम नहीं करता है? यह बहुत अच्छा सवाल नहीं है - क्या हुआ? कोई त्रुटि? क्या त्रुटियां हैं?
डैरेन स्वीनी


16
जवाब है प्रतिक्रिया में नेस्टेड राज्य का उपयोग न करें । पढ़िए यह बेहतरीन जवाब।
क्वर्टी

4
इसके बजाय क्या उपयोग किया जाना चाहिए?
जानिस एल्मरिस

42
बस नेस्टेड स्टेट का उपयोग नहीं करना इस बात का अस्वीकार्य जवाब है कि आज रिएक्ट का कितना व्यापक उपयोग किया जाता है। यह स्थिति सामने आने वाली है और डेवलपर्स को इसका जवाब चाहिए।
सेराओज़ेस

जवाबों:


454

आदेश करने के लिए setStateएक नेस्टेड वस्तु के लिए आप दृष्टिकोण नीचे का पालन कर सकते के रूप में मुझे लगता है कि setState नेस्ट अपडेट प्रबंधित नहीं करता है।

var someProperty = {...this.state.someProperty}
someProperty.flag = true;
this.setState({someProperty})

विचार यह है कि एक डमी ऑब्जेक्ट बनाया जाए, जो उस पर परिचालन करे और फिर अद्यतन ऑब्जेक्ट के साथ घटक की स्थिति को बदले

अब, प्रसार ऑपरेटर ऑब्जेक्ट की केवल एक स्तरीय नेस्टेड प्रतिलिपि बनाता है। यदि आपका राज्य अत्यधिक नस्टेड है:

this.state = {
   someProperty: {
      someOtherProperty: {
          anotherProperty: {
             flag: true
          }
          ..
      }
      ...
   }
   ...
}

आप प्रत्येक स्तर पर प्रसार ऑपरेटर का उपयोग करके सेट कर सकते हैं

this.setState(prevState => ({
    ...prevState,
    someProperty: {
        ...prevState.someProperty,
        someOtherProperty: {
            ...prevState.someProperty.someOtherProperty, 
            anotherProperty: {
               ...prevState.someProperty.someOtherProperty.anotherProperty,
               flag: false
            }
        }
    }
}))

हालाँकि उपरोक्त वाक्य रचना हर बदसूरत मिलती है क्योंकि राज्य अधिक से अधिक नेस्टेड हो जाता है और इसलिए मैं आपको immutability-helperराज्य को अपडेट करने के लिए पैकेज का उपयोग करने की सलाह देता हूं ।

राज्य के साथ अद्यतन करने के तरीके पर यह उत्तर देखें immutability helper


2
@Ohodwhy, नहीं, यह सीधे {@.state.someProperty} के बाद से राज्य तक नहीं पहुँच रहा है। somePropertyहम इस पर एक नया प्रतिबंध लगाते हैं और हम इसे संशोधित कर रहे हैं
शुभम खत्री

4
यह मेरे लिए काम नहीं किया .. मैं प्रतिक्रिया संस्करण @ 15.6.1 का उपयोग कर रहा हूं
राजीव

5
@Stophface हम लॉडश का उपयोग गहरी क्लोन सुनिश्चित करने के लिए कर सकते हैं, लेकिन हर कोई इस लाइब्रेरी को सिर्फ सेट करने के लिए शामिल नहीं करेगा
शुभम खत्री

15
क्या यह reactjs.org/docs/… का उल्लंघन नहीं करता है ? यदि नेस्टेड ऑब्जेक्ट में दो बदलावों को अंतिम रूप दिया जाता है, तो पहला परिवर्तन पहले ओवरराइट हो जाएगा। तो सबसे सही तरीका होगा: this.setState((prevState) => ({nested: {...prevState.nested, propertyToSet: newValue}}) थोडा थकाऊ हालांकि ...
olejorgenb

2
मुझे नहीं लगता कि आपको ...prevState,अंतिम उदाहरण की आवश्यकता है, आप केवल somePropertyऔर उसके बच्चों
जेमर जोन्स

140

इसे एक पंक्ति में लिखने के लिए

this.setState({ someProperty: { ...this.state.someProperty, flag: false} });

12
यह सीधे सेट करने के बजाय सेटस्टोर के लिए अपडेटर का उपयोग करने की सिफारिश की जाती है। reactjs.org/docs/react-component.html#setstate
रघु तेजा

6
मेरा मानना ​​है कि यह कह रहा है, के this.stateबाद तुरंत नहीं पढ़ता है setStateऔर उम्मीद है कि यह नया मूल्य है। बुला बनाम this.stateभीतर setState। या फिर बाद वाला मुद्दा भी है जो मेरे लिए स्पष्ट नहीं है?
trpt4him

2
जैसा कि trpt4him ने कहा, आपने जो लिंक दिया है, this.stateउसके बाद एक्सेस करने की समस्या के बारे में बात करता है setState। इसके अलावा, हम गुजर नहीं कर रहे हैं this.stateकरने के लिए setStateऑपरेटर प्रसार गुण। यह Object.assign () के समान है। github.com/tc39/proposal-object-rest-spread
Yoseph

3
@RaghuTeja शायद सिर्फ this.setState(currentState => { someProperty: { ...currentState.someProperty, flag: false} });इस मुद्दे से बचने की अनुमति दे सकता है?
वेबवैन

मैंने उत्तर जोड़ा है कि पूर्णता के लिए यूज़स्टेट हुक के साथ समान कैसे प्राप्त करें।
एंड्रयू

90

कभी-कभी सीधे उत्तर सबसे अच्छे नहीं होते हैं :)

लघु संस्करण:

यह कोड

this.state = {
    someProperty: {
        flag: true
    }
}

जैसा होना चाहिए वैसा ही सरलीकृत किया जाना चाहिए

this.state = {
    somePropertyFlag: true
}

दीर्घ संस्करण:

वर्तमान में आप रिएक्ट में नेस्टेड राज्य के साथ काम नहीं करना चाहिए । क्योंकि रिएक्टेड नेस्टेड राज्यों के साथ काम करने के लिए उन्मुख नहीं है और यहां प्रस्तावित सभी समाधान हैक के रूप में दिखते हैं। वे रूपरेखा का उपयोग नहीं करते हैं लेकिन इसके साथ लड़ते हैं। वे कुछ संपत्तियों के समूह के संदिग्ध उद्देश्य के लिए इतना स्पष्ट कोड नहीं लिखने का सुझाव देते हैं। इसलिए वे चुनौती के जवाब के रूप में बहुत दिलचस्प हैं लेकिन व्यावहारिक रूप से बेकार हैं।

निम्नलिखित स्थिति की कल्पना करें:

{
    parent: {
        child1: 'value 1',
        child2: 'value 2',
        ...
        child100: 'value 100'
    }
}

यदि आप सिर्फ एक मूल्य को बदल देंगे तो क्या होगा child1? प्रतिक्रिया दृश्य को फिर से प्रस्तुत नहीं करेगी क्योंकि यह उथले तुलना का उपयोग करती है और यह पाएगी कि parentसंपत्ति में बदलाव नहीं हुआ। BTW राज्य वस्तु को सीधे रूप से परिवर्तित करना सामान्य रूप से एक बुरा अभ्यास माना जाता है।

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

कुछ जटिल तर्क लिखकर उस समस्या को हल करना अभी भी संभव है, shouldComponentUpdate()लेकिन मैं यहां रुकना और छोटे संस्करण से सरल समाधान का उपयोग करना पसंद करूंगा।


4
मुझे लगता है कि ऐसे मामले हैं जहां एक नेस्टेड स्थिति पूरी तरह से ठीक है। जैसे कि एक राज्य गतिशील रूप से कुंजी-मूल्य जोड़े का ट्रैक रखता है। यहां देखें कि आप राज्य में केवल एक प्रविष्टि के लिए राज्य को कैसे अपडेट कर सकते हैं: reactjs.org/docs/…
pors

1
डिफ़ॉल्ट रूप से शुद्ध घटकों के लिए उथले तुलना का उपयोग किया जाता है।
बेसल शिशानी

4
मैं आपके सम्मान में एक वेदी बनाना चाहता हूं और हर सुबह प्रार्थना करता हूं। इस उत्तर तक पहुँचने में मुझे तीन दिन लग गए जो कि OBVIOUS डिज़ाइन निर्णय को पूरी तरह से समझाता है। हर कोई केवल फैल ऑपरेटर का उपयोग करने या अन्य हैक करने की कोशिश करता है, क्योंकि नेस्टेड स्थिति अधिक मानव-पठनीय लगती है।
इडेफ

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

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

61

अस्वीकरण

प्रतिक्रिया में नेस्टेड राज्य गलत डिजाइन है

पढ़िए यह बेहतरीन जवाब

 

इस उत्तर के पीछे तर्क:

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

class MyClass extends React.Component {
    myState = someObject
    inputValue = 42
...

MobX, उदाहरण के लिए, पूरी तरह से टाँके लगाता है और कस्टम अवलोकन योग्य गुणों का उपयोग करता है।
प्रतिक्रिया घटकों में राज्य के बजाय वेधशालाओं का उपयोग करें।

 


आपके दुख का जवाब - उदाहरण यहां देखें

जो भी नेस्टेड संपत्ति अद्यतन करने के लिए एक और छोटा तरीका है।

this.setState(state => {
  state.nested.flag = false
  state.another.deep.prop = true
  return state
})

एक लाइन पर

 this.setState(state => (state.nested.flag = false, state))

नोट: यह यहां कोमा ऑपरेटर ~ एमडीएन है , इसे यहां (सैंडबॉक्स) कार्रवाई में देखें ।

यह (हालांकि यह राज्य संदर्भ नहीं बदलता है) के समान है

this.state.nested.flag = false
this.forceUpdate()

इस संदर्भ में सूक्ष्म अंतर के लिए forceUpdateऔर setStateजुड़ा हुआ उदाहरण देखें।

बेशक यह कुछ मुख्य सिद्धांतों का दुरुपयोग कर रहा है, जैसा कि stateकेवल पढ़ा जाना चाहिए, लेकिन चूंकि आप तुरंत पुरानी स्थिति को छोड़ रहे हैं और इसे नए राज्य के साथ बदल रहे हैं, यह पूरी तरह से ठीक है।

चेतावनी

यहां तक कि घटक राज्य युक्त हालांकि होगा अद्यतन और rerender ठीक से ( यह पकड़ लिया छोड़कर ) , सहारा होगा असफल बच्चों को प्रचार करने के लिए (नीचे spymaster की टिप्पणी देखें) । केवल इस तकनीक का उपयोग करें यदि आप जानते हैं कि आप क्या कर रहे हैं।

उदाहरण के लिए, आप एक परिवर्तित फ्लैट प्रोप को पास कर सकते हैं जिसे अपडेट किया गया है और आसानी से पास किया गया है।

render(
  //some complex render with your nested state
  <ChildComponent complexNestedProp={this.state.nested} pleaseRerender={Math.random()}/>
)

अब भले ही complexNestedProp के लिए संदर्भ नहीं बदला है ( shouldComponentUpdate )

this.props.complexNestedProp === nextProps.complexNestedProp

जब भी मूल घटक अपडेट होता है, जो कॉल करने के बाद या माता-पिता में होता है, तो घटक फिर से प्रस्तुत करेगाthis.setStatethis.forceUpdate

राज्य को उत्परिवर्तित करने के प्रभाव

का उपयोग करते हुए नेस्टेड राज्य और सीधे राज्य परिवर्तनशील खतरनाक है क्योंकि विभिन्न वस्तुओं पैदा हो सकती हैं (जानबूझकर या बगैर) अलग (पुराने) के लिए संदर्भ राज्य और जरूरी जब अद्यतन करने के लिए पता नहीं हो सकता है (उदाहरण के लिए उपयोग करते समय PureComponentया अगर shouldComponentUpdateवापसी के लिए लागू किया जाता है false) या कर रहे हैं नीचे दिए गए उदाहरण में पुराने डेटा को प्रदर्शित करने का इरादा है।

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

राज्य के प्रवाह राज्य के प्रवाह नेस्ट

वैसे भी यहाँ आप देख सकते हैं कि Nested PureChildClassयह प्रचार करने में विफल होने के कारण पुन: नहीं चढ़ा।


12
आप कहीं भी किसी भी प्रतिक्रिया राज्य उत्परिवर्तन नहीं होना चाहिए। यदि ऐसे नेस्टेड घटक हैं जो स्टेट.नएस्टेड या स्टेट.ऑन्टर से डेटा का उपयोग करते हैं, तो वे अपने बच्चों को फिर से प्रस्तुत नहीं करेंगे और न ही करेंगे। इसका कारण यह है कि वस्तु नहीं बदली, इस प्रकार रिएक्ट को लगता है कि कुछ भी नहीं बदला है।
ज़रागंबा

@ SpyMaster356 मैंने इसे संबोधित करने के लिए अपना उत्तर अपडेट कर दिया है। यह भी ध्यान दें कि MobX, उदाहरण के लिए, stateपूरी तरह से ditches और कस्टम अवलोकन गुणों का उपयोग करता है । रिएक्ट setStateसिर्फ एक अंतर्निहित सुविधा है, लेकिन आप जल्द ही महसूस करते हैं कि इसकी सीमाएं हैं। कस्टम गुण और बुद्धिमान उपयोग का उपयोग forceUpdateआपको बहुत अधिक देता है। प्रतिक्रिया घटकों में राज्य के बजाय वेधशालाओं का उपयोग करें।
क्वर्टी

इसके अलावा, मैंने एक उदाहरण दिया- रिएक्शन्स -हेरोकैप्प्प्स / स्टेट-फ्लो (शीर्ष पर गिट से लिंक)
क्वर्टी

यदि आप उदाहरण के लिए किसी वस्तु को राज्य में डेटाबेस से नेस्टेड विशेषताओं के साथ लोड करते हैं तो क्या होगा? उस स्थिति में नेस्टेड स्थिति से कैसे बचें?
तोबिव

3
@tobiv यह एक लाने पर डेटा को एक अलग संरचना में बदलने के लिए बेहतर है, लेकिन यह usecase पर निर्भर करता है। यदि आप उन्हें कुछ डेटा की कॉम्पैक्ट यूनिट के रूप में सोचते हैं, तो एक नेस्टेड ऑब्जेक्ट या राज्य में ऑब्जेक्ट्स की सरणी होना ठीक है । समस्या तब उत्पन्न होती है जब आपको यूआई स्विच या अन्य अवलोकन योग्य डेटा (यानी डेटा को तुरंत दृश्य बदलना चाहिए) को स्टोर करने की आवश्यकता होती है, क्योंकि आंतरिक रिएक्ट डिफरिंग एल्गोरिदम को सही ढंग से ट्रिगर करने के लिए उन्हें सपाट होना चाहिए। अन्य नेस्टेड ऑब्जेक्ट्स में बदलाव के लिए, this.forceUpdate()विशिष्ट को ट्रिगर या कार्यान्वित करना आसान है shouldComponentUpdate
क्वर्टी

21

यदि आप ES2015 का उपयोग कर रहे हैं तो आपके पास Object.assign तक पहुंच है। आप इसका उपयोग नेस्टेड ऑब्जेक्ट को अपडेट करने के लिए निम्नानुसार कर सकते हैं।

this.setState({
  someProperty: Object.assign({}, this.state.someProperty, {flag: false})
});

आप मौजूदा के साथ अद्यतन गुणों को मर्ज करते हैं और लौटे ऑब्जेक्ट का उपयोग करके राज्य को अपडेट करते हैं।

संपादित करें: असाइन किए गए फ़ंक्शन को लक्ष्य के रूप में एक खाली ऑब्जेक्ट जोड़ा गया, यह सुनिश्चित करने के लिए कि राज्य सीधे रूप से उत्परिवर्तित नहीं है क्योंकि क्लार्क को इंगित किया गया है।


12
और मैं गलत हो सकता है, लेकिन मुझे नहीं लगता कि आप ES2015 के बिना रिएक्ट का उपयोग कर रहे हैं ।
मडब्रेक्स

16
const newState = Object.assign({}, this.state);
newState.property.nestedProperty = "new value";
this.setState(newState);

1
यहाँ और अधिक सुरुचिपूर्ण समाधान लगता है, 1) सेटस्टेट के अंदर थकाऊ फैलने से बचना और 2) सेटस्टेट के अंदर अच्छी तरह से नई स्थिति डालते हैं, सीधे सेटस्टेट के अंदर म्यूट करने से बचते हैं। अंतिम लेकिन कम से कम 3) सिर्फ एक साधारण कार्य के लिए किसी भी पुस्तकालय के उपयोग से बचना
Webwoman

दो उदाहरण समतुल्य नहीं हैं। यदि propertyकई नेस्टेड गुण हैं, तो पहला उन्हें हटा देगा, दूसरा नहीं होगा। codeandbox.io/s/nameless-pine-42thu
क्वर्टी

क्वर्टी, आप सही हैं, इस प्रयास के लिए धन्यवाद। मैंने ईएस 6 संस्करण को हटा दिया।
eyecandy.dev

Straighforward और सरल!
टोनी सीपिया

मैंने आपके समाधान का उपयोग किया। मेरा राज्य obj छोटा है, और इसने ठीक काम किया है। क्या बदले हुए राज्य के लिए रिएक्ट केवल प्रस्तुत करेगा या यह सब कुछ प्रस्तुत करेगा?
केंजी नोगुची

14

इसमें मदद करने के लिए कई पुस्तकालय हैं। उदाहरण के लिए, अपरिवर्तनीयता-सहायक का उपयोग करना :

import update from 'immutability-helper';

const newState = update(this.state, {
  someProperty: {flag: {$set: false}},
};
this.setState(newState);

लॉश / fp सेट का उपयोग करना :

import {set} from 'lodash/fp';

const newState = set(["someProperty", "flag"], false, this.state);

लॉश / fp मर्ज का उपयोग करना :

import {merge} from 'lodash/fp';

const newState = merge(this.state, {
  someProperty: {flag: false},
});

यदि आप उपयोग करते हैं lodash, तो आप संभवतः _.cloneDeepक्लोन कॉपी के लिए राज्य को सेट करने का प्रयास करना चाहते हैं ।
Yixing लियू

@YixingLiu: मैंने उपयोग करने का उत्तर अपडेट कर दिया है lodash/fp, इसलिए हमें म्यूटेशन के बारे में चिंता करने की आवश्यकता नहीं है।
टोकन जूल 26'18

सिंटैक्स के अलावा लॉश / एफपी में चुनने mergeया setकार्यों का कोई लाभ ?
Toivo Säwén

अच्छा जवाब, शायद आप जोड़ना चाहते हैं कि आपको this.setState(newState)लॉश / fp तरीकों के लिए भी कॉल करना है। एक और गेटा यह है कि लॉश .set(नॉन-एफपी) में तर्कों का एक अलग क्रम होता है जिसने मुझे थोड़ी देर के लिए उलझा दिया।
विवो सेवेन

7

इस प्रकार के मुद्दों को संभालने के लिए हम Immer https://github.com/mweststrate/immer का उपयोग करते हैं।

बस हमारे एक घटक में इस कोड को बदल दिया

this.setState(prevState => ({
   ...prevState,
        preferences: {
            ...prevState.preferences,
            [key]: newValue
        }
}));

इसके साथ

import produce from 'immer';

this.setState(produce(draft => {
    draft.preferences[key] = newValue;
}));

इमेर के साथ आप अपने राज्य को "सामान्य वस्तु" के रूप में संभालते हैं। जादू छद्म वस्तुओं के साथ दृश्य के पीछे होता है।


6

इस धागे में दिए गए पहले उत्तर पर एक भिन्नता है जिसके लिए किसी अतिरिक्त पैकेज, लाइब्रेरी या विशेष कार्यों की आवश्यकता नहीं है।

state = {
  someProperty: {
    flag: 'string'
  }
}

handleChange = (value) => {
  const newState = {...this.state.someProperty, flag: value}
  this.setState({ someProperty: newState })
}

किसी विशिष्ट नेस्टेड फ़ील्ड की स्थिति सेट करने के लिए, आपने संपूर्ण ऑब्जेक्ट सेट किया है। मैंने एक चर बनाकर, newStateऔर ES2015 प्रसार ऑपरेटर का उपयोग करके पहले इसमें वर्तमान स्थिति की सामग्री को फैलाया । फिर, मैंने this.state.flagनए मूल्य के साथ मूल्य बदल दिया (जब से मैंने वर्तमान स्थिति को ऑब्जेक्ट में फैलाने के flag: value बाद सेट किया , वर्तमान स्थिति में flagफ़ील्ड ओवरराइड है)। फिर, मैंने बस somePropertyअपनी newStateवस्तु की स्थिति निर्धारित की ।


6

हालांकि घोंसले के शिकार वास्तव में नहीं है कि आपको एक घटक राज्य का इलाज कैसे करना चाहिए, कभी-कभी एकल स्तरीय घोंसले के शिकार के लिए कुछ आसान होता है।

इस तरह एक राज्य के लिए

state = {
 contact: {
  phone: '888-888-8888',
  email: 'test@test.com'
 }
 address: {
  street:''
 },
 occupation: {
 }
}

एक फिर से प्रयोग करने योग्य विधि ive का उपयोग इस तरह दिखेगा।

handleChange = (obj) => e => {
  let x = this.state[obj];
  x[e.target.name] = e.target.value;
  this.setState({ [obj]: x });
};

तो बस प्रत्येक घोंसले के लिए obj नाम से गुजर रहा है जिसे आप संबोधित करना चाहते हैं ...

<TextField
 name="street"
 onChange={handleChange('address')}
 />

4

मैंने इस समाधान का उपयोग किया।

यदि आपके पास इस तरह एक नेस्टेड राज्य है:

   this.state = {
          formInputs:{
            friendName:{
              value:'',
              isValid:false,
              errorMsg:''
            },
            friendEmail:{
              value:'',
              isValid:false,
              errorMsg:''
            }
}

आप करंट चेंज फंक्शन की घोषणा कर सकते हैं जो करंट स्टेटस को कॉपी करता है और इसे बदले हुए मानों के साथ फिर से असाइन करता है

handleChange(el) {
    let inputName = el.target.name;
    let inputValue = el.target.value;

    let statusCopy = Object.assign({}, this.state);
    statusCopy.formInputs[inputName].value = inputValue;

    this.setState(statusCopy);
  }

यहाँ घटना श्रोता के साथ html

<input type="text" onChange={this.handleChange} " name="friendName" />

की पुष्टि। यह बहुत अच्छा काम करता है यदि आप पहले से ही नेस्टेड गुणों के साथ पहले से ही स्थापित प्रोजेक्ट के साथ काम कर रहे हैं।
धातु_जैक 1

4

राज्य की एक प्रति बनाएँ:

let someProperty = JSON.parse(JSON.stringify(this.state.someProperty))

इस वस्तु में परिवर्तन करें:

someProperty.flag = "false"

अब राज्य को अद्यतन करें

this.setState({someProperty})

setState एसिंक्रोनस है। इसलिए जब यह अपडेट होता है, तो कोई और इस फ़ंक्शन को कॉल कर सकता है और राज्य के पुराने संस्करण की प्रतिलिपि बना सकता है।
अवीव बेन शबात

3

यद्यपि आपने कक्षा-आधारित रिएक्ट घटक की स्थिति के बारे में पूछा था, वही समस्या यूज़स्टैट हुक के साथ मौजूद है। इससे भी बदतर: useState हुक आंशिक अद्यतन स्वीकार नहीं करता है। इसलिए यह सवाल बहुत प्रासंगिक हो गया जब यूज़स्ट्रेट हुक पेश किया गया।

मैंने यह सुनिश्चित करने के लिए निम्नलिखित उत्तर पोस्ट करने का फैसला किया है कि प्रश्न अधिक आधुनिक परिदृश्यों को शामिल करता है जहां यूज़स्ट्रेट हुक का उपयोग किया जाता है:

यदि आपको मिल गया है:

const [state, setState] = useState({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })

उदाहरण के लिए, आप मौजूदा क्लोनिंग और डेटा के आवश्यक सेगमेंट को पैच करके नेस्टेड संपत्ति सेट कर सकते हैं:

setState(current => { ...current, someProperty: { ...current.someProperty, flag: false } });

या आप ऑब्जेक्ट के क्लोनिंग और पैचिंग को आसान बनाने के लिए इमर लाइब्रेरी का उपयोग कर सकते हैं।

या आप केवल जटिल (स्थानीय और वैश्विक) राज्य डेटा के प्रबंधन को पूरी तरह से प्रबंधित करने और प्रदर्शन में सुधार करने के लिए हुकस्टेट लाइब्रेरी (अस्वीकरण: मैं एक लेखक हूं) का उपयोग कर सकता हूं (पढ़ें: प्रतिपादन अनुकूलन के बारे में चिंता न करें):

import { useStateLink } from '@hookstate/core' 
const state = useStateLink({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })

रेंडर करने के लिए फ़ील्ड प्राप्त करें:

state.nested.someProperty.nested.flag.get()
// or 
state.get().someProperty.flag

नेस्टेड फ़ील्ड सेट करें:

state.nested.someProperty.nested.flag.set(false)

यहां हुकस्टेट उदाहरण है, जहां राज्य वृक्ष की तरह डेटा संरचना में गहरा / पुनरावर्ती रूप से घोंसला है ।


2

दो अन्य विकल्पों का उल्लेख अभी तक नहीं किया गया है:

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

2

चीजों को सामान्य बनाने के लिए, मैंने @ शुभम खत्री और @ क्वर्टी के उत्तरों पर काम किया।

राज्य की वस्तु

this.state = {
  name: '',
  grandParent: {
    parent1: {
      child: ''
    },
    parent2: {
      child: ''
    }
  }
};

इनपुट नियंत्रण

<input
  value={this.state.name}
  onChange={this.updateState}
  type="text"
  name="name"
/>
<input
  value={this.state.grandParent.parent1.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent1.child"
/>
<input
  value={this.state.grandParent.parent2.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent2.child"
/>

अद्यतन विधि

@ शुभम खत्री के उत्तर के रूप में सेट करें

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const oldstate = this.state;
  const newstate = { ...oldstate };
  let newStateLevel = newstate;
  let oldStateLevel = oldstate;

  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      newStateLevel[path[i]] = event.target.value;
    } else {
      newStateLevel[path[i]] = { ...oldStateLevel[path[i]] };
      oldStateLevel = oldStateLevel[path[i]];
      newStateLevel = newStateLevel[path[i]];
    }
  }
  this.setState(newstate);
}

@ Qwerty के उत्तर के रूप में सेट करें

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const state = { ...this.state };
  let ref = state;
  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      ref[path[i]] = event.target.value;
    } else {
      ref = ref[path[i]];
    }
  }
  this.setState(state);
}

नोट: ये उपरोक्त विधियाँ सरणियों के लिए काम नहीं करेंगी


2

मैं आपके घटक राज्य की पूरी प्रतिलिपि बनाने के बारे में पहले से ही उठ रही चिंताओं को बहुत गंभीरता से लेता हूं । उस के साथ, मैं दृढ़ता से Immer सुझाव देंगे ।

import produce from 'immer';

<Input
  value={this.state.form.username}
  onChange={e => produce(this.state, s => { s.form.username = e.target.value }) } />

इसके लिए काम करना चाहिए React.PureComponent(यानी रिएक्ट द्वारा उथले राज्य की तुलना) क्योंकि Immerचतुराई से एक मनमाने ढंग से गहरे राज्य के पेड़ को कुशलता से कॉपी करने के लिए एक प्रॉक्सी ऑब्जेक्ट का उपयोग करता है। इमटेरिटी हेल्पर जैसी पुस्तकालयों की तुलना में इम्मर भी अधिक प्रकार के हैं, और जावास्क्रिप्ट और टाइपस्क्रिप्ट उपयोगकर्ताओं के लिए एक जैसे आदर्श हैं।


टाइपस्क्रिप्ट उपयोगिता फ़ंक्शन

function setStateDeep<S>(comp: React.Component<any, S, any>, fn: (s: 
Draft<Readonly<S>>) => any) {
  comp.setState(produce(comp.state, s => { fn(s); }))
}

onChange={e => setStateDeep(this, s => s.form.username = e.target.value)}

1
stateUpdate = () => {
    let obj = this.state;
    if(this.props.v12_data.values.email) {
      obj.obj_v12.Customer.EmailAddress = this.props.v12_data.values.email
    }
    this.setState(obj)
}

1
मुझे नहीं लगता कि यह सही है, क्योंकि objयह केवल राज्य का एक संदर्भ है, इसलिए इसके माध्यम से आप वास्तविक this.stateवस्तु को बदल रहे हैं
Ciprian Tomoiagă

0

मुझे यह मेरे लिए काम करने के लिए मिला, मेरे मामले में एक प्रोजेक्ट फॉर्म है जहां उदाहरण के लिए आपके पास एक आईडी है, और एक नाम और मैं एक नेस्टेड प्रोजेक्ट के लिए राज्य बनाए रखना चाहूंगा।

return (
  <div>
      <h2>Project Details</h2>
      <form>
        <Input label="ID" group type="number" value={this.state.project.id} onChange={(event) => this.setState({ project: {...this.state.project, id: event.target.value}})} />
        <Input label="Name" group type="text" value={this.state.project.name} onChange={(event) => this.setState({ project: {...this.state.project, name: event.target.value}})} />
      </form> 
  </div>
)

मुझे बताएं!


0

ऐसा कुछ हो सकता है,

const isObject = (thing) => {
    if(thing && 
        typeof thing === 'object' &&
        typeof thing !== null
        && !(Array.isArray(thing))
    ){
        return true;
    }
    return false;
}

/*
  Call with an array containing the path to the property you want to access
  And the current component/redux state.

  For example if we want to update `hello` within the following obj
  const obj = {
     somePrimitive:false,
     someNestedObj:{
        hello:1
     }
  }

  we would do :
  //clone the object
  const cloned = clone(['someNestedObj','hello'],obj)
  //Set the new value
  cloned.someNestedObj.hello = 5;

*/
const clone = (arr, state) => {
    let clonedObj = {...state}
    const originalObj = clonedObj;
    arr.forEach(property => {
        if(!(property in clonedObj)){
            throw new Error('State missing property')
        }

        if(isObject(clonedObj[property])){
            clonedObj[property] = {...originalObj[property]};
            clonedObj = clonedObj[property];
        }
    })
    return originalObj;
}

const nestedObj = {
    someProperty:true,
    someNestedObj:{
        someOtherProperty:true
    }
}

const clonedObj = clone(['someProperty'], nestedObj);
console.log(clonedObj === nestedObj) //returns false
console.log(clonedObj.someProperty === nestedObj.someProperty) //returns true
console.log(clonedObj.someNestedObj === nestedObj.someNestedObj) //returns true

console.log()
const clonedObj2 = clone(['someProperty','someNestedObj','someOtherProperty'], nestedObj);
console.log(clonedObj2 === nestedObj) // returns false
console.log(clonedObj2.someNestedObj === nestedObj.someNestedObj) //returns false
//returns true (doesn't attempt to clone because its primitive type)
console.log(clonedObj2.someNestedObj.someOtherProperty === nestedObj.someNestedObj.someOtherProperty) 

0

मुझे पता है कि यह एक पुराना सवाल है, लेकिन फिर भी मैं इसे हासिल करना चाहता हूं। निर्माणकर्ता राज्य को इस तरह देखता है:

  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      user: {
        email: ""
      },
      organization: {
        name: ""
      }
    };

    this.handleChange = this.handleChange.bind(this);
  }

मेरा handleChangeकार्य इस प्रकार है:

  handleChange(e) {
    const names = e.target.name.split(".");
    const value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
    this.setState((state) => {
      state[names[0]][names[1]] = value;
      return {[names[0]]: state[names[0]]};
    });
  }

और सुनिश्चित करें कि आप तदनुसार इनपुट नाम दें:

<input
   type="text"
   name="user.email"
   onChange={this.handleChange}
   value={this.state.user.firstName}
   placeholder="Email Address"
/>

<input
   type="text"
   name="organization.name"
   onChange={this.handleChange}
   value={this.state.organization.name}
   placeholder="Organization Name"
/>

0

मैं कम खोज के साथ नेस्टेड अपडेट करता हूं :

उदाहरण:

राज्य में नेस्टेड चर:

state = {
    coords: {
        x: 0,
        y: 0,
        z: 0
    }
}

कार्यक्रम:

handleChange = nestedAttr => event => {
  const { target: { value } } = event;
  const attrs = nestedAttr.split('.');

  let stateVar = this.state[attrs[0]];
  if(attrs.length>1)
    attrs.reduce((a,b,index,arr)=>{
      if(index==arr.length-1)
        a[b] = value;
      else if(a[b]!=null)
        return a[b]
      else
        return a;
    },stateVar);
  else
    stateVar = value;

  this.setState({[attrs[0]]: stateVar})
}

उपयोग:

<input
value={this.state.coords.x}
onChange={this.handleTextChange('coords.x')}
/>

0

यह मेरा इनिशिएटिव है

    const initialStateInput = {
        cabeceraFamilia: {
            familia: '',
            direccion: '',
            telefonos: '',
            email: ''
        },
        motivoConsulta: '',
        fechaHora: '',
        corresponsables: [],
    }

हुक या आप इसे राज्य (वर्ग घटक) से बदल सकते हैं

const [infoAgendamiento, setInfoAgendamiento] = useState(initialStateInput);

हैंडल चेंज के लिए विधि

const actualizarState = e => {
    const nameObjects = e.target.name.split('.');
    const newState = setStateNested(infoAgendamiento, nameObjects, e.target.value);
    setInfoAgendamiento({...newState});
};

नेस्टेड राज्यों के साथ सेट राज्य के लिए विधि

const setStateNested = (state, nameObjects, value) => {
    let i = 0;
    let operativeState = state;
    if(nameObjects.length > 1){
        for (i = 0; i < nameObjects.length - 1; i++) {
            operativeState = operativeState[nameObjects[i]];
        }
    }
    operativeState[nameObjects[i]] = value;
    return state;
}

अंत में यह वह इनपुट है जो मैं उपयोग करता हूं

<input type="text" className="form-control" name="cabeceraFamilia.direccion" placeholder="Dirección" defaultValue={infoAgendamiento.cabeceraFamilia.direccion} onChange={actualizarState} />

0

यदि आप अपने प्रोजेक्ट में फॉर्मिक का उपयोग कर रहे हैं, तो इस सामान को संभालने का कुछ आसान तरीका है। यहां फॉर्मिक के साथ सबसे आसान तरीका है।

पहले अपने प्रारंभिक मानों को फॉर्मिक इनिटिवल्यूस विशेषता के अंदर या प्रतिक्रिया में सेट करें। राज्य

यहाँ, प्रारंभिक मान प्रतिक्रिया अवस्था में परिभाषित किया गया है

   state = { 
     data: {
        fy: {
            active: "N"
        }
     }
   }

फॉर्मिक initiValuesविशेषता के अंदर फॉर्मिक फ़ील्ड के लिए शुरुआती चरणों से ऊपर परिभाषित करें

<Formik
 initialValues={this.state.data}
 onSubmit={(values, actions)=> {...your actions goes here}}
>
{({ isSubmitting }) => (
  <Form>
    <Field type="checkbox" name="fy.active" onChange={(e) => {
      const value = e.target.checked;
      if(value) setFieldValue('fy.active', 'Y')
      else setFieldValue('fy.active', 'N')
    }}/>
  </Form>
)}
</Formik>

राज्य को सेट करने stringके booleanलिए फॉर्मिक setFieldValueफ़ंक्शन के बजाय अपडेट किए गए राज्य को चेक करने के लिए एक कंसोल बनाएं या फ़ॉरबाइड फॉर्मिक राज्य मानों को देखने के लिए प्रतिक्रिया डिबगर टूल के साथ जाएं।


0

इस कोड को आज़माएं:

this.setState({ someProperty: {flag: false} });

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

0

मैंने एक पुस्तक में निम्नलिखित देखा:

this.setState(state => state.someProperty.falg = false);

लेकिन मुझे यकीन नहीं है कि अगर यह सही है ..

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