ReactJS'de durum dizilerinin doğru modifikasyonu


416

Bir statedizinin sonuna bir öğe eklemek istiyorum , bu doğru şekilde mi?

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

Ben dizi yerinde yerinde değişiklik pushsorun neden olabilir endişe - güvenli mi?

Dizinin bir kopyasını yapmanın ve setStateisraflı görünmenin alternatifi .


9
Bence reaksiyon değişmezliği yardımcıları kullanabilirsiniz. bkz. facebook.github.io/react/docs/update.html#simple-push
nilgun

Durum dizisinde setState çözümümü kontrol et. <br/> <br> stackoverflow.com/a/59711447/9762736
Rajnikant Lodhi

Yanıtlar:


763

Docs tepki diyor ki:

Bunu tedavi edin. Değişmezmiş gibi davranın.

Sizin pushdevleti doğrudan dönüşecek ve tekrar sonradan devlet "sıfırlama" ediyor olsa bile, potansiyel olarak, eğilimli kod hata neden olabilir. F.ex, gibi bazı yaşam döngüsü yöntemlerinin componentDidUpdatetetiklenmemesine yol açabilir .

Sonraki React sürümlerinde önerilen yaklaşım, yarış koşullarını önlemek için durumları değiştirirken bir güncelleyici işlevi kullanmaktır :

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

Bellek "atık", standart olmayan durum değişikliklerini kullanırken karşılaşabileceğiniz hatalarla karşılaştırıldığında bir sorun değildir.

Önceki React sürümleri için alternatif sözdizimi

concatYeni bir dizi döndürdüğü için temiz bir sözdizimi almak için kullanabilirsiniz :

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

ES6'da Spread Operator uygulamasını kullanabilirsiniz :

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

8
Bir yarış koşulunun ne zaman ortaya çıkacağına dair bir örnek verebilir misiniz?
soundly_typed

3
@Qiming pushyeni dizi uzunluğunu döndürür, böylece çalışmaz. Ayrıca, setStatezaman uyumsuzdur ve React birkaç durum değişikliğini tek bir render geçişine sıralayabilir.
David Hellsing

2
@mindeavor, this.state parametrelerini arayan bir animationFrame'iniz ve durum değişikliğindeki diğer bazı parametreleri değiştiren başka bir yönteminiz olduğunu söylüyor. SetState eşzamansız olduğundan, durumun değiştiği ancak değişikliği dinleyen yönteme yansımadığı bazı kareler olabilir.
David Hellsing

1
@ChristopherCamps Bu cevap setStateiki kez aramayı teşvik etmez , durum dizisini doğrudan mutasyona uğratmadan ayarlamanın iki benzer örneğini gösterir.
David Hellsing

2
Bir durum dizisini bugünlerde değişmez olarak görmenin kolay bir yolu şudur: let list = Array.from(this.state.list); list.push('woo'); this.setState({list});Elbette stil tercihlerinize göre değiştirin.
basicdays

133

Kullanıyorsanız en kolayı ES6.

initialArray = [1, 2, 3];

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

Yeni dizi [1,2,3,4]

React'taki durumunuzu güncellemek için

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

Dizi yok etme hakkında daha fazla bilgi edinin


@Muzietto biraz ayrıntı verebilir misiniz?
StateLess

4
Bu sorunun temel noktası, dizileri değiştirmemek, Tepki durumunu değiştirmek. Ne demek istediğimi kendin gördün ve cevabını düzenledin. Bu, cevabınızı alakalı hale getirir. Aferin.
Marco Faustinelli

2
Sorularınız OP sorusunu doğrudan ilgilendirmiyor
StateLess

1
@ChanceSmith: StateLess yanıtında da gereklidir . Durum güncellemesine devletin kendisine bağlı olmayın. Resmi doktor: reaktjs.org/docs/…
arcol

1
@RayCoder günlüğü ve dizivar değerini kontrol, dizi değil gibi görünüyor.
StateLess

57

En basit yol ES6:

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

Üzgünüm, benim durumumda dizi içine bir dizi itmek istiyorum. tableData = [['test','test']]Sonra benim yeni dizi itti tableData = [['test','test'],['new','new']]. @David ve @Ridd nasıl itilir
Johncy

@Johncy Denemek istiyorsanız [['test','test'],['new','new']]:this.setState({ tableData: [...this.state.tableData, ['new', 'new']]
Ridd

this.setState({ tableData: [...this.state.tableData ,[item.student_name,item.homework_status_name,item.comments===null?'-':item.comments] ] });Yeni diziyi iki kez ekler. this.state.tableData.push([item.student_name,item.homework_status_name,item.comments===null?'-':item.comments]);İstediğim şeyi elde eder. ama bence doğru şekilde değil.
Johncy

26

React güncellemeleri toplu hale getirebilir ve bu nedenle doğru yaklaşım setState'e güncellemeyi gerçekleştiren bir işlev sağlamaktır.

React güncelleme eklentisi için aşağıdakiler güvenilir bir şekilde çalışır:

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

veya concat () için:

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

Aşağıda, yanlış yaparsanız ne olduğuna örnek olarak https://jsbin.com/mofekakuqi/7/edit?js,output öğesinin ne olduğunu gösterir .

SetTimeout () çağırma doğru bir şekilde üç öğe ekledi çünkü React bir setTimeout geri çağrısında toplu güncellemeler yapmayacak (bkz. Https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ ).

Buggy onClick yalnızca "Üçüncü" ekleyecek, ancak sabit olan, beklendiği gibi F, S ve T ekleyecektir.

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'));

Gerçekten olduğu bir durum var mı? Sadece yaparsakthis.setState( update(this.state, {array: {$push: ["First", "Second", "Third"]}}) )
Albizia

1
@Albizia Sanırım bir meslektaş bulmalı ve onlarla tartışmalısınız. Yalnızca bir setState çağrısı yapıyorsanız herhangi bir toplu işlem sorunu yoktur. Mesele React toplu güncellemeleri, yani evet ... gerçekten bir durum var, yukarıdaki kod JSBin sürümünde bulabileceğiniz şey budur. Bu konudaki hemen hemen tüm cevaplar bunu ele
almıyor

state.array = state.array.concat([4])bu önceki durum nesnesini değiştirir.
Emile Bergeron

1
@EmileBergeron Kalıcılığınız için teşekkür ederiz. Sonunda geriye baktım ve beynimin neyi görmeyi reddettiğini gördüm ve belgeleri kontrol ettim, bu yüzden düzenleyeceğim.
NealeU

1
İyi! JS'deki değişmezlik belli olmadığından (bir kütüphanenin API'siyle uğraşırken daha da fazla) yanlış olmak gerçekten çok kolay.
Emile Bergeron


3

Fonksiyonel bileşen kullanıyorsanız lütfen bunu aşağıdaki gibi kullanın.

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

Diziye yeni eleman eklemek push()için cevap olmalı.

Öğeyi kaldır ve dizinin güncelleme durumu için aşağıdaki kod benim için çalışıyor. splice(index, 1)Çalışamayız.

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

Bir dizi durumda değeri itmek ve böyle bir değer ayarlamak ve devlet dizi tanımlamak ve harita fonksiyonu ile değeri itmek çalışıyorum.

 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

Bu benim için bir dizi içine bir dizi eklemek için çalıştı

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

0

İşte başkalarına yardım edebileceğini düşündüğüm 2020 Reactjs Hook örneği. Bir Reactjs tablosuna yeni satırlar eklemek için kullanıyorum. Bir şey üzerinde gelişebilirsem bana bildirin.

İşlevsel durum bileşenine yeni bir öğe ekleme:

Durum verilerini tanımlayın:

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

Bir düğmenin yeni bir öğe eklemek için bir işlevi tetiklemesini sağlayın

<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
Bu yazının düşük kaliteli posta olarak kabul edilmesini önlemek için biraz açıklama ekleyin stackoverflow.
Harsha Biyani

2
@ Bu çağrıyı ES6'da "yayma operatörü" yapın ve dizi2'ye dizi2 öğelerini ekleyin. downvote için teşekkürler (:
M.Samiei

@ M.Samiei Downvotes önlemek için yayınınızı düzenlemeniz gerekir. Sadece bir kod snippet'i olarak düşük kalite. Ayrıca, güncellemeler toplu olabileceği için durumu bu şekilde değiştirmek tehlikelidir, bu yüzden tercih edilen yol örneğinsetState(state => ({arrayvar: [...state.arrayvar, ...newelement]}) );
NealeU

ve newelementnesneyi bir dizi içine yaymak TypeErroryine de atar .
Emile Bergeron

-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

Bu kod benim için çalışıyor:

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

2
yine de, durumu doğrudan mutasyona uğratıyorsun
Asbar Ali

2
Ve bir dizi değil, .pushbir sayı döndürdüğü için bileşenin durumunu doğru güncelleştiremiyor .
Emile Bergeron
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.