प्रतिक्रिया में setState के साथ एक वस्तु को अद्यतन करना


265

क्या वस्तु के गुणों को अद्यतन करना संभव है setState?

कुछ इस तरह:

this.state = {
   jasper: { name: 'jasper', age: 28 },
}

मैंने कोशिश की है:

this.setState({jasper.name: 'someOtherName'});

और इस:

this.setState({jasper: {name: 'someothername'}})

सिंटैक्स त्रुटि में पहला परिणाम और दूसरा कुछ नहीं करता है। कोई विचार?


5
दूसरा कोड काम किया होगा, लेकिन आपने ageसंपत्ति खो दी होगी jasper
जार्ज

जवाबों:


576

ऐसा करने के कई तरीके हैं, चूंकि राज्य अपडेट एक एसिंक्स ऑपरेशन है , इसलिए राज्य ऑब्जेक्ट को अपडेट करने के लिए, हमें अपडेटर फ़ंक्शन के साथ उपयोग करना होगा setState

1- सबसे सरल:

पहले उसकी एक प्रति बनाएँ jasperफिर उसमें बदलाव करें:

this.setState(prevState => {
  let jasper = Object.assign({}, prevState.jasper);  // creating copy of state variable jasper
  jasper.name = 'someothername';                     // update the name property, assign a new value                 
  return { jasper };                                 // return new object jasper object
})

उपयोग करने के बजाय Object.assignहम इसे इस तरह भी लिख सकते हैं:

let jasper = { ...prevState.jasper };

2- प्रसार ऑपरेटर का उपयोग करना :

this.setState(prevState => ({
    jasper: {                   // object that we want to update
        ...prevState.jasper,    // keep all other key-value pairs
        name: 'something'       // update the value of specific key
    }
}))

नोट: Object.assign और Spread Operatorकेवल उथली प्रतिलिपि बनाता है , इसलिए यदि आपने नेस्टेड ऑब्जेक्ट या ऑब्जेक्ट की सरणी को परिभाषित किया है, तो आपको एक अलग दृष्टिकोण की आवश्यकता है।


नेस्टेड स्टेट ऑब्जेक्ट को अपडेट करना:

मान लें कि आपने राज्य को इस प्रकार परिभाषित किया है:

this.state = {
  food: {
    sandwich: {
      capsicum: true,
      crackers: true,
      mayonnaise: true
    },
    pizza: {
      jalapeno: true,
      extraCheese: false
    }
  }
}

पिज्जा ऑब्जेक्ट की अतिरिक्त मात्रा को अद्यतन करने के लिए:

this.setState(prevState => ({
  food: {
    ...prevState.food,           // copy all other key-value pairs of food object
    pizza: {                     // specific object of food object
      ...prevState.food.pizza,   // copy all pizza key-value pairs
      extraCheese: true          // update value of specific key
    }
  }
}))

वस्तुओं की अद्यतन सारणी:

मान लें कि आपके पास एक टूडू ऐप है, और आप इस रूप में डेटा का प्रबंधन कर रहे हैं:

this.state = {
  todoItems: [
    {
      name: 'Learn React Basics',
      status: 'pending'
    }, {
      name: 'Check Codebase',
      status: 'pending'
    }
  ]
}

किसी भी टॉड ऑब्जेक्ट की स्थिति को अपडेट करने के लिए, ऐरे पर एक मैप चलाएं और प्रत्येक ऑब्जेक्ट के कुछ अनूठे मान के लिए जाँच करें, यदि condition=trueकोई नई वस्तु लौटाए, तो अपडेटेड वैल्यू के साथ, वही ऑब्जेक्ट।

let key = 2;
this.setState(prevState => ({

  todoItems: prevState.todoItems.map(
    el => el.key === key? { ...el, status: 'done' }: el
  )

}))

सुझाव: यदि ऑब्जेक्ट का कोई विशिष्ट मान नहीं है, तो सरणी इंडेक्स का उपयोग करें।


जिस तरह से मैं अब कोशिश कर रहा था वह काम करता है ... दूसरा तरीका: एस
जॉन्सन

7
@ जोहान्सवेयर में आप दूसरे से jasperवस्तु से अन्य गुणों को हटा देंगे , क्या console.log(jasper)आप केवल एक कुंजी देखेंगे name, उम्र नहीं होगी :)
मयंक शुक्ला

1
@ जॉनसन, हाँ यह तरीका उचित है यदि jasperकोई है object, तो सबसे अच्छा है या नहीं, अन्य बेहतर समाधान संभव हो सकते हैं :)
मयंक शुक्ला

6
यहां उल्लेख करने के लिए अच्छा है कि न तो Object.assignऔर न ही ऑपरेटर गहरी कॉपी गुणों का प्रसार करें। इस तरह से आपको वर्कअराउंड्स जैसे कि लॉश deepCopyआदि का उपयोग करना चाहिए
एलेक्स

1
कैसे मुकाबला let { jasper } = this.state?
ब्रायन ले

37

यह सबसे तेज़ और सबसे पठनीय तरीका है:

this.setState({...this.state.jasper, name: 'someothername'});

यहां तक ​​कि अगर this.state.jasperपहले से ही एक नाम संपत्ति है, तो नए नाम name: 'someothername'का उपयोग किया जाना चाहिए।


38
इस समाधान में एक बड़ा नुकसान है: राज्य अद्यतनों का अनुकूलन करने के लिए प्रतिक्रिया कई अद्यतनों को समूहित कर सकती है। एक परिणाम के रूप में this.state.jasperजरूरी नहीं कि नवीनतम अवस्था हो। के साथ संकेतन का बेहतर उपयोग करें prevState
पाप किया

33

स्प्रेड ऑपरेटर और कुछ ES6 का उपयोग करें

this.setState({
    jasper: {
          ...this.state.jasper,
          name: 'something'
    }
})

यह जस्पर को अपडेट करता है लेकिन अन्य संपत्तियों को राज्य से हटा दिया जाता है।
iaq

11

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

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

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" />

यह मेरे लिए काम कर रहा था, सिवाय इसके कि मुझे इसका इस्तेमाल करना था:statusCopy.formInputs[inputName] = inputValue;
मिकी

9

मुझे पता है कि यहां बहुत सारे उत्तर हैं, लेकिन मुझे आश्चर्य है कि उनमें से कोई भी सेटस्टेट के बाहर नई वस्तु की प्रतिलिपि नहीं बनाता है, और फिर बस सेट करें ({newObject})। स्वच्छ, संक्षिप्त और विश्वसनीय। तो इस मामले में:

const jasper = { ...this.state.jasper, name: 'someothername' }
this.setState(() => ({ jasper }))

या एक गतिशील संपत्ति के लिए (रूपों के लिए बहुत उपयोगी)

const jasper = { ...this.state.jasper, [VarRepresentingPropertyName]: 'new value' }
this.setState(() => ({ jasper }))


7

यह कोशिश करो, यह ठीक काम करना चाहिए

this.setState(Object.assign(this.state.jasper,{name:'someOtherName'}));

4
आप सीधे राज्य ऑब्जेक्ट को म्यूट कर रहे हैं। इस दृष्टिकोण का उपयोग करने के लिए, स्रोत के रूप में एक नई वस्तु जोड़ें:Object.assign({}, this.state.jasper, {name:'someOtherName'})
अल्बिजिया

3

पहला मामला वास्तव में एक वाक्यविन्यास त्रुटि है।

चूँकि मैं आपके बाकी घटक को नहीं देख सकता, इसलिए यह देखना मुश्किल है कि आप अपने राज्य में वस्तुओं को यहाँ क्यों फेंक रहे हैं। यह घटक राज्य में वस्तुओं को घोंसले के लिए एक अच्छा विचार नहीं है। अपना प्रारंभिक राज्य स्थापित करने का प्रयास करें:

this.state = {
  name: 'jasper',
  age: 28
}

इस तरह, यदि आप नाम अपडेट करना चाहते हैं, तो आप कॉल कर सकते हैं:

this.setState({
  name: 'Sean'
});

क्या वह हासिल करेंगे जो आप के लिए लक्ष्य कर रहे हैं?

बड़े, अधिक जटिल डेटा स्टोर के लिए, मैं Redux जैसी किसी चीज़ का उपयोग करूंगा। लेकिन यह बहुत अधिक उन्नत है।

घटक राज्य के साथ सामान्य नियम केवल घटक की UI स्थिति (जैसे सक्रिय, टाइमर, आदि) का प्रबंधन करने के लिए इसका उपयोग करना है।

ये संदर्भ देखें:


1
मैंने केवल इसका उपयोग एक उदाहरण के रूप में किया है, ऑब्जेक्ट को नेस्टेड किया जाना चाहिए .. मुझे शायद Redux का उपयोग करना चाहिए लेकिन मैं रिएक्ट fundementals समझने की कोशिश कर रहा हूं ..
JohnSnow

2
हाँ, मैं अब Redux से दूर रहूँगा। जब आप बुनियादी बातों को सीख रहे हैं, तो अपने डेटा को सरल रखने का प्रयास करें। इससे आपको अजीब मामलों से बचने में मदद मिलेगी जो आपकी यात्रा करते हैं। 👍
McCambridge

2

एक अन्य विकल्प: अपने वेरिएबल को जैस्पर ऑब्जेक्ट से बाहर परिभाषित करें और फिर एक वेरिएबल को कॉल करें।

प्रसार ऑपरेटर: ES6

this.state = {  jasper: { name: 'jasper', age: 28 } } 

let foo = "something that needs to be saved into state" 

this.setState(prevState => ({
    jasper: {
        ...jasper.entity,
        foo
    }
})

2

सरल और गतिशील तरीका।

यह काम करेगा, लेकिन आपको सभी आईडी माता-पिता को सेट करने की आवश्यकता है, इसलिए माता-पिता ऑब्जेक्ट के नाम को इंगित करेंगे, आईडी = "जैस्पर" होगा और इनपुट तत्व का नाम = ऑब्जेक्ट जैस्पर के अंदर का नाम ।

handleChangeObj = ({target: { id , name , value}}) => this.setState({ [id]: { ...this.state[id] , [name]: value } });

मैं पहली पंक्ति से सहमत हूं, क्योंकि यह एकमात्र ऐसी चीज है जो राज्य में वस्तुओं की मेरी वस्तु के लिए काम करती है! इसके अलावा यह साफ हो गया कि मैं अपने डेटा को अपडेट करने में कहां फंस गया हूं। अब तक का सबसे सरल और गतिशील तरीका ... धन्यवाद !!
स्मिट करें

2

आप इसके साथ प्रयास कर सकते हैं : ( नोट : इनपुट टैग का नाम = वस्तु का क्षेत्र)

<input name="myField" type="text" 
      value={this.state.myObject.myField} 
     onChange={this.handleChangeInpForm}>
</input>

-----------------------------------------------------------
handleChangeInpForm = (e) => {
   let newObject = this.state.myObject;
   newObject[e.target.name] = e.target.value;
   this.setState({
     myObject: newObject 
   })
}

ढेर अतिप्रवाह में आपका स्वागत है। हालांकि यह कोड प्रश्न का उत्तर दे सकता है, लेकिन यह कोड क्यों और / या इस प्रश्न के उत्तर के बारे में अतिरिक्त संदर्भ प्रदान करता है, इसके दीर्घकालिक मूल्य में सुधार करता है। उत्तर कैसे दें
Elletlar

2

इस का उपयोग करते हुए एक अन्य समाधान है इम्मेर immutabe उपयोगिता, बहुत आसानी से गहरा नेस्टेड वस्तुओं के लिए अनुकूल है, और आप उत्परिवर्तन के बारे में परवाह नहीं करना चाहिए

this.setState(
    produce(draft => {
       draft.jasper.name = 'someothername
    })
)

1

इसके अलावा, अल्बर्टो पिरस समाधान के बाद, यदि आप सभी "राज्य" ऑब्जेक्ट को कॉपी नहीं करना चाहते हैं:

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

    let jasperCopy = Object.assign({}, this.state.jasper);
    jasperCopy[inputName].name = inputValue;

    this.setState({jasper: jasperCopy});
  }

1

आप इसके साथ प्रयास कर सकते हैं:

this.setState(prevState => {
   prevState = JSON.parse(JSON.stringify(this.state.jasper));
   prevState.name = 'someOtherName';
   return {jasper: prevState}
})

या अन्य संपत्ति के लिए:

this.setState(prevState => {
   prevState = JSON.parse(JSON.stringify(this.state.jasper));
   prevState.age = 'someOtherAge';
   return {jasper: prevState}
})

या आप हैंडलचेज फ़ंक्शन का उपयोग कर सकते हैं:

handleChage(event) {
   const {name, value} = event.target;
    this.setState(prevState => {
       prevState = JSON.parse(JSON.stringify(this.state.jasper));
       prevState[name] = value;
       return {jasper: prevState}
    })
}

और HTML कोड:

<input 
   type={"text"} 
   name={"name"} 
   value={this.state.jasper.name} 
   onChange={this.handleChange}
/>
<br/>
<input 
   type={"text"} 
   name={"age"} 
   value={this.state.jasper.age} 
   onChange={this.handleChange}
/>

यह JSON.stringify के बिना काम करता है .. this.setState (prevState => {prevState = this.state.document; prevState.ValidDate = event.target.value; prevState.VideDateFormat = dayFormat; return {document: prevState}); ..जब दस्तावेज राज्य प्रकार वस्तु है ..
ओलेग बोरोडको

1

Async और Await का उपयोग किए बिना इसका उपयोग करें ...

funCall(){    
     this.setState({...this.state.jasper, name: 'someothername'});
}

यदि आप Async और Await के साथ इसका उपयोग कर रहे हैं ...

async funCall(){
      await this.setState({...this.state.jasper, name: 'someothername'});
}

0

इस सेटअप ने मेरे लिए काम किया:

let newState = this.state.jasper;
newState.name = 'someOtherName';

this.setState({newState: newState});

console.log(this.state.jasper.name); //someOtherName
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.