ReactJS में राज्य सरणियों का सही संशोधन


416

मैं एक stateसरणी के अंत में एक तत्व जोड़ना चाहता हूं , क्या यह ऐसा करने का सही तरीका है?

this.state.arrayvar.push(newelement);
this.setState({arrayvar:this.state.arrayvar});

मुझे चिंता है कि सरणी में जगह को संशोधित करने से pushपरेशानी हो सकती है - क्या यह सुरक्षित है?

सरणी की प्रतिलिपि बनाने का विकल्प, और setStateआईएनजी जो बेकार लगता है।


9
मुझे लगता है कि आप प्रतिक्रिया अपरिवर्तनीय सहायकों का उपयोग कर सकते हैं। इसे देखें: facebook.github.io/react/docs/update.html#simple-push
nilgun

राज्य सरणी में सेट करें मेरा समाधान देखें। <br/> <br> stackoverflow.com/a/59711447/9762736
रजनीकांत लोधी

जवाबों:


763

प्रतिक्रिया डॉक्स का कहना है:

यह समझो कि यह अपरिवर्तनीय है।

आपका pushराज्य सीधे बदल जाएगा और संभावित रूप से त्रुटि प्रवण कोड हो सकता है, भले ही आप राज्य को फिर से "रीसेट" कर रहे हों। F.ex, यह कुछ जीवनचक्र विधियों componentDidUpdateको ट्रिगर नहीं कर सकता है।

बाद के रिएक्शन संस्करणों में अनुशंसित दृष्टिकोण दौड़ की स्थिति को रोकने के लिए राज्यों को संशोधित करते समय एक अपडेटर फ़ंक्शन का उपयोग करना है :

this.setState(prevState => ({
  arrayvar: [...prevState.arrayvar, newelement]
}))

गैर-मानक राज्य संशोधनों का उपयोग करते हुए त्रुटियों की तुलना में मेमोरी "अपशिष्ट" एक मुद्दा नहीं है।

पहले प्रतिक्रिया संस्करणों के लिए वैकल्पिक वाक्यविन्यास

जब आप concatएक नया सरणी लौटाते हैं, तो आप एक स्वच्छ वाक्यविन्यास प्राप्त करने के लिए उपयोग कर सकते हैं :

this.setState({ 
  arrayvar: this.state.arrayvar.concat([newelement])
})

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

this.setState({
  arrayvar: [...this.state.arrayvar, newelement]
})

8
क्या आप एक उदाहरण दे सकते हैं कि रेस की स्थिति कब होगी?
sound_typed 2:11 पर

3
@Qiming pushनई सरणी लंबाई देता है ताकि काम नहीं करेगा। इसके अलावा, setStateasync और React एक ही रेंडर पास में कई राज्य परिवर्तनों को कतारबद्ध कर सकते हैं।
डेविड हेलसिंग जूल

2
@mindeavor का कहना है कि आपके पास एक एनिमेशनफ्रेम है जो इस पैरामीटर में दिखता है। स्टेट और दूसरा तरीका जो राज्य परिवर्तन पर कुछ अन्य मापदंडों को बदलता है। कुछ फ्रेम हो सकते हैं जहां राज्य बदल गया है, लेकिन उस पद्धति में नहीं दिखता है जो परिवर्तन के लिए सुनता है, क्योंकि setState async है।
डेविड हेलसिंग

1
@ChristopherCamps यह उत्तर setStateदो बार कॉल करने के लिए प्रोत्साहित नहीं करता है , यह सीधे राज्य परिवर्तन के बिना राज्य सरणी सेट करने के दो समान उदाहरण दिखाता है।
डेविड हेल्सिंग

2
राज्य सरणी को इन दिनों अपरिवर्तनीय मानने का एक आसान तरीका है: let list = Array.from(this.state.list); list.push('woo'); this.setState({list});अपनी शैली की प्राथमिकताओं में बदलाव करें।
बेसिकडे

133

सबसे आसान, यदि आप उपयोग कर रहे हैं ES6

initialArray = [1, 2, 3];

newArray = [ ...initialArray, 4 ]; // --> [1,2,3,4]

नई व्यूह रचना होगी [1,2,3,4]

प्रतिक्रिया में अपने राज्य को अद्यतन करने के लिए

this.setState({
         arrayvar:[...this.state.arrayvar, newelement]
       });

सरणी विनाश के बारे में अधिक जानें


@Muzietto आप विस्तृत कर सकते हैं?
स्टेटलैस

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

2
आपके प्रश्न सीधे ओपी प्रश्न की चिंता नहीं करते
StateLess

1
@ChanceSmith: StateLess जवाब में भी इसकी जरूरत है। राज्य पर ही राज्य के अपडेट पर निर्भर न रहें। आधिकारिक दस्तावेज़: reactjs.org/docs/...
arcol

1
@RayCoder लॉग इन करें और arrayvar के मान की जाँच करें, ऐसा लगता है कि यह सरणी नहीं है।
स्टेटलेस

57

सबसे सरल तरीका ES6:

this.setState(prevState => ({
    array: [...prevState.array, newElement]
}))

क्षमा करें, मेरे मामले में मैं एक सरणी को सरणी में धकेलना चाहता हूं। tableData = [['test','test']]धक्का देने के बाद मेरी नई सरणी tableData = [['test','test'],['new','new']]। इस @ शिवाय और @ रिड को कैसे आगे बढ़ाया जाए
जॉसी

@ जॉनी यदि आप [['test','test'],['new','new']]कोशिश करना चाहते हैं :this.setState({ tableData: [...this.state.tableData, ['new', 'new']]
रिड

this.setState({ tableData: [...this.state.tableData ,[item.student_name,item.homework_status_name,item.comments===null?'-':item.comments] ] });यह दो बार नई सरणी सम्मिलित करता है this.state.tableData.push([item.student_name,item.homework_status_name,item.comments===null?'-':item.comments]);यह वांछित चीज़ को प्राप्त करता है जिसे मैं चाहता हूं। लेकिन इसका सही तरीका मुझे नहीं लगता।
जॉनी

26

प्रतिक्रिया बैच अपडेट कर सकती है, और इसलिए सही तरीका यह है कि अपडेट को निष्पादित करने वाले फ़ंक्शन के साथ सेटस्ट्रेट प्रदान करें।

प्रतिक्रिया अद्यतन addon के लिए, निम्नलिखित मज़बूती से काम करेगा:

this.setState( state => update(state, {array: {$push: [4]}}) );

या समवर्ती के लिए ():

this.setState( state => ({
    array: state.array.concat([4])
}));

निम्नलिखित दिखाता है कि https://jsbin.com/mofekakuqi/7/edit?js,output उदाहरण के रूप में क्या होता है यदि आप इसे गलत पाते हैं।

सेटटाइमआउट () इनवोकेशन सही ढंग से तीन आइटम जोड़ता है क्योंकि रिएक्ट एक सेटटाइमआउट कॉलबैक के भीतर बैच अपडेट नहीं करेगा (देखें https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYR2zK9dEJ )।

छोटी गाड़ी onClick केवल "तीसरा" जोड़ेगी, लेकिन निश्चित एक, अपेक्षित रूप से F, S और T जोड़ देगा।

class List extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      array: []
    }

    setTimeout(this.addSome, 500);
  }

  addSome = () => {
      this.setState(
        update(this.state, {array: {$push: ["First"]}}));
      this.setState(
        update(this.state, {array: {$push: ["Second"]}}));
      this.setState(
        update(this.state, {array: {$push: ["Third"]}}));
    };

  addSomeFixed = () => {
      this.setState( state => 
        update(state, {array: {$push: ["F"]}}));
      this.setState( state => 
        update(state, {array: {$push: ["S"]}}));
      this.setState( state => 
        update(state, {array: {$push: ["T"]}}));
    };



  render() {

    const list = this.state.array.map((item, i) => {
      return <li key={i}>{item}</li>
    });
       console.log(this.state);

    return (
      <div className='list'>
        <button onClick={this.addSome}>add three</button>
        <button onClick={this.addSomeFixed}>add three (fixed)</button>
        <ul>
        {list}
        </ul>
      </div>
    );
  }
};


ReactDOM.render(<List />, document.getElementById('app'));

क्या वास्तव में ऐसा कोई मामला है जहां ऐसा होता है? अगर हम बस करते हैंthis.setState( update(this.state, {array: {$push: ["First", "Second", "Third"]}}) )
अल्बिजिया

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

state.array = state.array.concat([4])यह पिछले राज्य ऑब्जेक्ट को म्यूट करता है।
एमिल बर्जरॉन

1
@EmileBergeron आपकी दृढ़ता के लिए धन्यवाद। मैंने अंततः पीछे मुड़कर देखा कि मेरा दिमाग क्या देख रहा था और डॉक्स की जाँच करने से इनकार कर रहा था, इसलिए मैं संपादित करूँगा।
नेलेउ

1
अच्छा! जेएस में अपरिवर्तनीयता के रूप में गलत होना वास्तव में आसान है, गैर-स्पष्ट है (एक पुस्तकालय के एपीआई के साथ काम करते समय और भी अधिक)।
एमिल बर्जरॉन

17

टिप्पणी में उल्लिखित @nilgun के रूप में, आप प्रतिक्रिया अपरिवर्तनीयता सहायकों का उपयोग कर सकते हैं । मैंने इसे सुपर उपयोगी पाया है।

डॉक्स से:

साधारण धक्का

var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]

आरंभिक ऐरे अभी भी [1, 2, 3] है।


6
प्रतिक्रिया अपरिवर्तनीय सहायकों को प्रलेखन में पदावनत के रूप में वर्णित किया गया है। अब इसके बजाय github.com/kolodny/immutability-helper का उपयोग किया जाना चाहिए।
पेरियाटा ब्रीटाटा

3

यदि आप कार्यात्मक घटक का उपयोग कर रहे हैं तो कृपया नीचे दिए अनुसार इसका उपयोग करें।

const [chatHistory, setChatHistory] = useState([]); // define the state

const chatHistoryList = [...chatHistory, {'from':'me', 'message':e.target.value}]; // new array need to update
setChatHistory(chatHistoryList); // update the state

1

सरणी में जोड़े गए नए तत्व के लिए, push()उत्तर होना चाहिए।

एलीमेंट को हटाने और अपडेट करने की स्थिति के लिए, मेरे लिए नीचे कोड काम करता है। splice(index, 1)काम नहीं कर सकता।

const [arrayState, setArrayState] = React.useState<any[]>([]);
...

// index is the index for the element you want to remove
const newArrayState = arrayState.filter((value, theIndex) => {return index !== theIndex});
setArrayState(newArrayState);

0

मैं एक सरणी स्थिति में मान पुश करने का प्रयास कर रहा हूं और इस तरह मान सेट करता हूं और राज्य सरणी को परिभाषित करता हूं और मानचित्र फ़ंक्शन द्वारा धक्का मूल्य।

 this.state = {
        createJob: [],
        totalAmount:Number=0
    }


 your_API_JSON_Array.map((_) => {
                this.setState({totalAmount:this.state.totalAmount += _.your_API_JSON.price})
                this.state.createJob.push({ id: _._id, price: _.your_API_JSON.price })
                return this.setState({createJob: this.state.createJob})
            })

0

इसने मेरे लिए एक सरणी में एक सरणी जोड़ने का काम किया

this.setState(prevState => ({
    component: prevState.component.concat(new Array(['new', 'new']))
}));

0

यहाँ एक 2020, Reactjs हुक उदाहरण है जो मुझे लगा कि दूसरों की मदद कर सकता है। मैं इसका उपयोग रिएक्ट्स टेबल में नई पंक्तियों को जोड़ने के लिए कर रहा हूं। मुझे पता है कि मैं कुछ पर सुधार कर सकते हैं।

एक कार्यात्मक राज्य घटक में एक नया तत्व जोड़ना:

राज्य डेटा परिभाषित करें:

    const [data, setData] = useState([
        { id: 1, name: 'John', age: 16 },
        { id: 2, name: 'Jane', age: 22 },
        { id: 3, name: 'Josh', age: 21 }
    ]);

एक बटन को एक नया तत्व जोड़ने के लिए एक फ़ंक्शन ट्रिगर करें

<Button
    // pass the current state data to the handleAdd function so we can append to it.
    onClick={() => handleAdd(data)}>
    Add a row
</Button>
function handleAdd(currentData) {

        // return last data array element
        let lastDataObject = currentTableData[currentTableData.length - 1]

        // assign last elements ID to a variable.
        let lastID = Object.values(lastDataObject)[0] 

        // build a new element with a new ID based off the last element in the array
        let newDataElement = {
            id: lastID + 1,
            name: 'Jill',
            age: 55,
        }

        // build a new state object 
        const newStateData = [...currentData, newDataElement ]

        // update the state
        setData(newStateData);

        // print newly updated state
        for (const element of newStateData) {
            console.log('New Data: ' + Object.values(element).join(', '))
        }

}

-1
this.setState({
  arrayvar: [...this.state.arrayvar, ...newelement]
})

2
इस पोस्ट को निम्न गुणवत्ता वाले पोस्ट के रूप में मानने से बचने के लिए कुछ स्पष्टीकरण जोड़ें stackoverflow
हर्षा बियानी

2
@ इस कॉल को ES6 में "प्रसार ऑपरेटर" और array1 आइटम array1 में जोड़ें।
डाउनवोट के

@ M.Samiei आपको अपने पोस्ट को डाउनवोट से बचने के लिए संपादित करने की आवश्यकता है। यह सिर्फ एक कोड स्निपेट के रूप में कम गुणवत्ता है। इसके अलावा, राज्य को इस तरह से संशोधित करना खतरनाक है क्योंकि अपडेट को बैच दिया जा सकता है, इसलिए पसंदीदा तरीका हैsetState(state => ({arrayvar: [...state.arrayvar, ...newelement]}) );
NealeU

और newelementएक सरणी के भीतर वस्तु को फैलाना TypeErrorवैसे भी फेंकता है ।
एमिल बर्जरॉन

-1
//------------------code is return in typescript 

const updateMyData1 = (rowIndex:any, columnId:any, value:any) => {

    setItems(old => old.map((row, index) => {
        if (index === rowIndex) {
        return Object.assign(Object.assign({}, old[rowIndex]), { [columnId]: value });
    }
    return row;
}));

-6

यह कोड मेरे लिए काम करता है:

fetch('http://localhost:8080')
  .then(response => response.json())
  .then(json => {
    this.setState({mystate: this.state.mystate.push.apply(this.state.mystate, json)})
  })

2
फिर भी, आप सीधे राज्य को बदल देते हैं
असबर अली

2
और .pushनंबर वापस करने के बाद से घटक की स्थिति को सही ढंग से अपडेट करने में विफल रहता है , एक सरणी नहीं।
एमिल बर्जरॉन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.