Menghapus elemen dari array dalam status komponen

131

Saya mencoba menemukan cara terbaik untuk menghapus elemen dari array dalam keadaan komponen. Karena saya tidak boleh memodifikasi this.statevariabel secara langsung, apakah ada cara yang lebih baik (lebih ringkas) untuk menghapus elemen dari array daripada yang saya miliki di sini ?:

  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
    })
  },

Terima kasih.

diperbarui

Ini telah diperbarui untuk menggunakan panggilan balik di setState. Ini harus dilakukan ketika merujuk kondisi saat ini saat memperbaruinya.

aherriot
sumber
Lihatlah ImmutableJS dari Facebook yang berfungsi baik dengan React. tautan
Jonatan Lundqvist Medén
6
Saya tidak melihat ada yang salah dengan kode Anda. Sebenarnya itu cara yang sangat idiomatis untuk melakukannya.
Dimitar Dimitrov

Jawaban:

138

Cara terbersih untuk melakukan ini yang saya lihat adalah dengan filter:

removeItem(index) {
  this.setState({
    data: this.state.data.filter((_, i) => i !== index)
  });
}
ephrion
sumber
18
@ HussienK _kadang-kadang digunakan untuk mewakili argumen yang tidak digunakan. Di sini, ini adalah item saat ini dalam array.
chrisM
1
Luar biasa. Saya menggunakan .filter sepanjang waktu tetapi tidak pernah mempertimbangkan untuk menggunakannya dalam situasi ini. : D
dakt
4
Ini adalah kode bersih, namun, untuk array besar, metode ini lambat. Alasannya, itu loop melalui seluruh array untuk menemukan indeks yang terlihat sudah ditentukan.
Matt Ellis
1
@MattEllis Karena pembaruan status React tidak dapat diubah, Anda akan dikenakan O (n) dalam ukuran daftar untuk menyalinnya dalam keadaan apa pun. Saya akan terkejut jika ini adalah hit kinerja yang signifikan.
ephrion
4
Mengevaluasi this.statesebagai masukan untuk this.setState(), bahkan secara tetap, tidak direkomendasikan. silakan lihat jawaban saya di atas untuk referensi ke dokumen Bereaksi resmi tentang topik ini.
pscl
87

Anda dapat menggunakan bantuan update()immutability darireact-addons-update , yang secara efektif melakukan hal yang sama di bawah tenda, tetapi apa yang Anda lakukan baik-baik saja.

this.setState(prevState => ({
  data: update(prevState.data, {$splice: [[index, 1]]})
}))
Jonny Buchanan
sumber
Contoh yang jauh lebih sederhana daripada yang Anda tautkan :)
Koen.
7
react-addons-updatesekarang tidak digunakan lagi (2016). immutability-helpertersedia sebagai pengganti. github.com/kolodny/immutability-helper Juga silakan lihat jawaban saya di bawah ini tentang tidak bermutasi this.state langsung di dalam this.setState ().
pscl
62

Saya percaya referensi this.statedi dalam setState()tidak disarankan ( Pembaruan Negara Mungkin Tidak Sinkron ).

Docs merekomendasikan penggunaan setState()dengan fungsi callback sehingga prevState diteruskan saat runtime ketika pembaruan terjadi. Jadi begini tampilannya:

Menggunakan Array.prototype.filter tanpa ES6

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

Menggunakan Array.prototype.filter dengan ES6 Arrow Functions

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

Menggunakan immutability-helper

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

Menggunakan Spread

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

Perhatikan bahwa dalam setiap contoh, terlepas dari teknik yang digunakan, this.setState()diteruskan dengan panggilan balik, bukan referensi objek ke yang lama this.state;

pscl
sumber
3
Ini adalah jawaban yang benar, lihat juga The Power of Not Mutating Data
Vinnie James
1
Contohnya menggunakan callback prevState dengan berbagai teknik ditambahkan.
pscl
bagaimana jika saya melakukannya seperti ini? this.setState({ data: [...this.state.data.slice(0, index), ...this.state.data.slice(index + 1)] }); apakah salah menggunakan this.statebukan prevStateopsi callback yang ditunjukkan oleh @ user1628461?
Tiberiu Maxim
Ini adalah solusi terbaik, meskipun tidak sederhana
Developia
terima kasih, menggunakan spreadnya memungkinkan untuk memperbarui elemen di tengah juga daripada menghapusnya, itulah yang saya butuhkan.
Vaibhav Vishal
24

Berikut adalah cara untuk menghapus elemen dari array di negara bagian menggunakan sintaks menyebar ES6.

onRemovePerson: (index) => {
  const data = this.state.data;
  this.setState({ 
    data: [...data.slice(0,index), ...data.slice(index+1)]
  });
}
evianpring
sumber
1
Terima kasih! Ini terasa seperti cara paling alami untuk melakukannya.
fabiomaia
3

Saya ingin berpadu di sini meskipun pertanyaan ini sudah dijawab dengan benar oleh @pscl jika ada orang lain yang mengalami masalah yang sama saya lakukan. Dari 4 metode memberi saya memilih untuk menggunakan sintaks es6 dengan fungsi panah karena itu keringkasan dan kurangnya ketergantungan pada perpustakaan eksternal:

Menggunakan Array.prototype.filter dengan ES6 Arrow Functions

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

Seperti yang Anda lihat, saya membuat sedikit modifikasi untuk mengabaikan jenis indeks ( !==untuk !=) karena dalam kasus saya, saya mengambil indeks dari bidang string.

Hal lain yang bermanfaat jika Anda melihat perilaku aneh ketika menghapus elemen di sisi klien adalah untuk TIDAK PERNAH menggunakan indeks array sebagai kunci untuk elemen :

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

Ketika Bereaksi berbeda dengan DOM virtual pada perubahan, itu akan melihat tombol untuk menentukan apa yang telah berubah. Jadi jika Anda menggunakan indeks dan ada satu yang kurang dalam array, itu akan menghapus yang terakhir. Alih-alih, gunakan id konten sebagai kunci, seperti ini.

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

Di atas adalah kutipan dari jawaban ini dari pos terkait .

Selamat Mengkode Semuanya!

c0d3ster
sumber
1

Anda dapat menggunakan fungsi ini, jika Anda ingin menghapus elemen (tanpa indeks)

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

Seperti disebutkan dalam komentar untuk jawaban ephrion di atas, filter () bisa lambat, terutama dengan array besar, karena loop untuk mencari indeks yang tampaknya sudah ditentukan. Ini adalah solusi yang bersih, tetapi tidak efisien.

Sebagai alternatif, seseorang dapat dengan mudah 'memotong' elemen yang diinginkan dan menyatukan fragmen-fragmen.

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

Semoga ini membantu!

Matt Ellis
sumber
0

Anda dapat membuat kode lebih mudah dibaca dengan fungsi pembantu satu baris:

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

lalu gunakan seperti ini:

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

Hanya sebuah saran, dalam kode Anda alih-alih menggunakan let newData = prevState.dataAnda dapat menggunakan spread yang diperkenalkan dalam ES6 yang dapat Anda gunakan let newData = ...prevState.data untuk menyalin array

Tiga titik ... mewakili Penyebar Operator atau Parameter Istirahat ,

Ini memungkinkan ekspresi array atau string atau apa pun yang dapat iterasi untuk diperluas di tempat-tempat di mana nol atau lebih argumen untuk panggilan fungsi atau elemen untuk array diharapkan.

Selain itu Anda dapat menghapus item dari array dengan mengikuti

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

Semoga ini berkontribusi !!

saddam kamal
sumber
-3

Berikut ini cara mudah untuk melakukannya:

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.
}

Semoga Membantu !!!

T04435
sumber
Mau jelaskan?
Tiberiu Maxim
5
Saya pikir itu karena deletemenghapus item tetapi indeks tidak diperbarui dan oleh karena itu ini bukan pendekatan yang baik untuk kebutuhan reguler.
Kunok