Bileşen durumunda diziden eleman çıkarma


131

Bileşen durumundaki bir diziden bir öğeyi kaldırmanın en iyi yolunu bulmaya çalışıyorum. this.stateDeğişkeni doğrudan değiştirmemem gerektiğine göre, burada sahip olduğumdan daha iyi (daha kısa) bir diziden bir elemanı kaldırmanın bir yolu var mı ?:

  onRemovePerson: function(index) {
    this.setState(prevState => { // pass callback in setState to avoid race condition
      let newData = prevState.data.slice() //copy array from prevState
      newData.splice(index, 1) // remove element
      return {data: newData} // update state
    })
  },

Teşekkür ederim.

güncellenmiş

Bu, setState'teki geri aramayı kullanmak için güncellendi. Bu, güncelleme sırasında mevcut duruma referans verilirken yapılmalıdır.


React ile iyi çalışan Facebook'tan ImmutableJS'e bir göz atın. bağlantı
Jonatan Lundqvist Medén

6
Kodunuzda yanlış bir şey görmüyorum. Aslında bunu yapmanın çok deyimsel bir yolu.
Dimitar Dimitrov

Yanıtlar:


138

Bunu yapmanın en temiz yolu şuydu filter:

removeItem(index) {
  this.setState({
    data: this.state.data.filter((_, i) => i !== index)
  });
}

18
@HussienK _, bazen kullanılmayan bir argümanı temsil etmek için kullanılır. Burada, dizideki mevcut öğe.
chrisM

1
İnanılmaz. Her zaman .filter kullanıyorum ama bu durumda kullanmayı asla düşünmedim. : D
dakt

4
Bu temiz koddur, ancak büyük diziler için bu yöntem yavaştır. Nedeni, önceden belirlenmiş gibi görünen bir dizini bulmak için tüm dizi boyunca döngü oluşturur.
Matt Ellis

1
@MattEllis React'in durum güncellemeleri yine de değişmez olduğundan, her durumda kopyalamak için listenin boyutunda O (n) ile karşılaşacaksınız. Bu önemli bir performans vuruşu olsaydı şaşırırdım.
ephrion

4
Değişmez bir şekilde bile this.stategirdi olarak değerlendirilmesi this.setState()tavsiye edilmez. bu konudaki resmi React belgelerine referans için lütfen yukarıdaki cevabıma bakın.
pscl

87

Kaputun altında aynı şeyi etkili bir şekilde yapan update()değişmezlik yardımcısınıreact-addons-update kullanabilirsiniz , ancak yaptığınız şey iyidir.

this.setState(prevState => ({
  data: update(prevState.data, {$splice: [[index, 1]]})
}))

Bağlantı kurduğunuzdan çok daha basit bir örnek :)
Koen.

7
react-addons-updateartık kullanımdan kaldırılmıştır (2016). immutability-helperyedek olarak mevcuttur. github.com/kolodny/immutability-helper Ayrıca lütfen this.state'i doğrudan this.setState () içinde değiştirmemekle ilgili cevabıma bakın.
pscl

62

this.stateİçine atıfta setState()bulunmanın tavsiye edilmediğine inanıyorum ( Durum Güncellemeleri Eşzamansız Olabilir ).

Dokümanlar setState(), güncelleme gerçekleştiğinde çalışma zamanında prevState'in iletilmesi için bir geri çağırma işleviyle kullanılmasını önerir . Öyleyse şöyle görünecek:

Array.prototype.filter'ı ES6 olmadan kullanma

removeItem : function(index) {
  this.setState(function(prevState){
    return { data : prevState.data.filter(function(val, i) {
      return i !== index;
    })};
  });
}

Array.prototype.filter'ı ES6 Ok İşlevleriyle Kullanma

removeItem(index) {
  this.setState((prevState) => ({
    data: prevState.data.filter((_, i) => i !== index)
  }));
}

Değişmezlik yardımcısı kullanma

import update from 'immutability-helper'
...
removeItem(index) {
  this.setState((prevState) => ({
    data: update(prevState.data, {$splice: [[index, 1]]})
  }))
}

Yaymayı kullanma

function removeItem(index) {
  this.setState((prevState) => ({
    data: [...prevState.data.slice(0,index), ...prevState.data.slice(index+1)]
  }))
}

Her durumda, kullanılan teknik ne olursa olsun , eskiye bir nesne başvurusu değilthis.setState() , bir geri arama geçirildiğini unutmayınthis.state ;


3
Bu doğru cevap, ayrıca bkz . Verileri Değiştirmeme Gücü
Vinnie James

1
PrevState geri aramasını çeşitli tekniklerle birlikte kullanan örnekler.
pscl

ya böyle yaparsam? @ user1628461 tarafından gösterilen geri arama seçeneği yerine this.setState({ data: [...this.state.data.slice(0, index), ...this.state.data.slice(index + 1)] }); kullanmak yanlış mı? this.stateprevState
Tiberiu Maxim

Bu, en basit olmasa da en iyi çözüm
Developia

teşekkürler, spread kullanarak bir öğeyi silmek yerine ortada güncellemek mümkün, ihtiyacım olan buydu.
Vaibhav Vishal

24

ES6 yayılma sözdizimini kullanarak öğeyi durumdaki diziden kaldırmanın bir yolu.

onRemovePerson: (index) => {
  const data = this.state.data;
  this.setState({ 
    data: [...data.slice(0,index), ...data.slice(index+1)]
  });
}

1
Teşekkürler! Bu, bunu yapmanın en doğal yolu gibi geliyor.
fabiomaia

3

Başka birinin yaptığım aynı sorunla karşılaşması durumunda , bu soru @pscl tarafından zaten doğru bir şekilde yanıtlanmış olsa da, burada zil çalmak istiyorum. Verilen 4 yöntemden, özlü olması ve harici kitaplıklara bağımlı olmaması nedeniyle es6 sözdizimini ok işlevleriyle kullanmayı seçtim:

Array.prototype.filter'ı ES6 Ok İşlevleriyle Kullanma

removeItem(index) {
  this.setState((prevState) => ({
    data: prevState.data.filter((_, i) => i != index)
  }));
}

Gördüğünüz gibi ben (Dizin tipini görmezden hafif bir değişiklik yapılmış !==için !=bir dize alanından endeksi alınırken çünkü benim durumumda).

İstemci tarafında bir öğeyi kaldırırken garip bir davranış görüyorsanız, başka bir yararlı nokta , bir dizinin dizinini ASLA öğe için anahtar olarak kullanmamaktır :

// bad
{content.map((content, index) =>
  <p key={index}>{content.Content}</p>
)}

React, bir değişiklik durumunda sanal DOM ile farklılık gösterdiğinde, neyin değiştiğini belirlemek için anahtarlara bakacaktır. Yani dizinler kullanıyorsanız ve dizide bir eksik varsa, sonuncuyu kaldıracaktır. Bunun yerine, içeriğin kimliklerini bunun gibi anahtar olarak kullanın.

// good
{content.map(content =>
  <p key={content.id}>{content.Content}</p>
)}

Yukarıdakiler, ilgili bir gönderiden bu yanıttan bir alıntıdır .

Herkese Mutlu Kodlama!


1

Öğeyi kaldırmak istiyorsanız bu işlevi kullanabilirsiniz (indeks olmadan)

removeItem(item) {
  this.setState(prevState => {
    data: prevState.data.filter(i => i !== item)
  });
}

1

Yukarıdaki ephrion'un cevabına yapılan bir yorumda belirtildiği gibi, filter (), önceden belirlenmiş gibi görünen bir dizini aramak için döngü oluşturduğundan, özellikle büyük dizilerde yavaş olabilir. Bu temiz ama verimsiz bir çözümdür.

Alternatif olarak, istenen öğeyi basitçe 'dilimleyebilir' ve parçaları birleştirebilirsiniz.

var dummyArray = [];    
this.setState({data: dummyArray.concat(this.state.data.slice(0, index), this.state.data.slice(index))})

Bu yardımcı olur umarım!


0

Tek satırlık bir yardımcı işlevle kodu daha okunaklı hale getirebilirsiniz:

const removeElement = (arr, i) => [...arr.slice(0, i), ...arr.slice(i+1)];

o zaman şu şekilde kullanın:

this.setState(state => ({ places: removeElement(state.places, index) }));

0

Sadece bir öneri, kodunuzda kullanmak yerine, diziyi kopyalamak için let newData = prevState.datakullanabileceğiniz ES6'da tanıtılan spread'i kullanabilirsiniz let newData = ...prevState.data .

Üç nokta ... Yayılma Operatörlerini veya Dinlenme Parametrelerini temsil eder ,

İşlev çağrıları için sıfır veya daha fazla argümanın veya dizi öğesinin beklendiği yerlerde bir dizi ifadesinin veya dizesinin veya yinelenebilen herhangi bir şeyin genişletilmesine izin verir.

Ek olarak, diziden aşağıdaki öğeyle silebilirsiniz:

onRemovePerson: function(index) {
  this.setState((prevState) => ({
    data: [...prevState.data.slice(0,index), ...prevState.data.slice(index+1)]
  }))
}

Umarım bu katkıda bulunur !!


-3

İşte bunu yapmanın basit bir yolu:

removeFunction(key){
  const data = {...this.state.data}; //Duplicate state.
  delete data[key];                  //remove Item form stateCopy.
  this.setState({data});             //Set state as the modify one.
}

Umarım yardımcı olur!!!


Açıklamak ister misin?
Tiberiu Maxim

5
Sanırım bunun nedeni deleteöğeyi kaldırması ancak dizinler güncellenmemesi ve bu nedenle bu, düzenli ihtiyaçlar için iyi bir yaklaşım olmayacaktır.
Kunok
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.