Loại bỏ phần tử khỏi mảng trong trạng thái thành phần


131

Tôi đang cố gắng tìm cách tốt nhất để loại bỏ một phần tử khỏi một mảng trong trạng thái của một thành phần. Vì tôi không nên sửa đổi this.statebiến trực tiếp, có cách nào tốt hơn (ngắn gọn hơn) để loại bỏ một phần tử khỏi một mảng so với những gì tôi có ở đây không?:

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

Cảm ơn bạn.

cập nhật

Điều này đã được cập nhật để sử dụng gọi lại trong setState. Điều này nên được thực hiện khi tham chiếu trạng thái hiện tại trong khi cập nhật nó.


Hãy xem ImmutableJS từ Facebook hoạt động tốt với React. liên kết
Jonatan Lundqvist Medén

6
Tôi không thấy bất cứ điều gì sai với mã của bạn. Trong thực tế, đó là cách rất thành ngữ để làm điều đó.
Dimitar Dimitrov

Câu trả lời:


138

Cách sạch nhất để làm điều này mà tôi đã thấy là filter:

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

18
@HussienK _đôi khi được sử dụng để thể hiện một đối số không được sử dụng. Đây là mục hiện tại trong mảng.
chrisM

1
Kinh ngạc. Tôi đang sử dụng .filter mọi lúc nhưng không bao giờ cân nhắc sử dụng nó trong tình huống này. : D
dakt

4
Đây là mã sạch, tuy nhiên, đối với các mảng lớn, phương pháp này chậm. Lý do là, nó lặp qua toàn bộ mảng để tìm một chỉ mục có vẻ đã được xác định.
Matt Ellis

1
@MattEllis Vì dù sao các cập nhật trạng thái của React là bất biến, nên bạn sẽ phải chịu O (n) trong kích thước của danh sách để sao chép nó trong mọi trường hợp. Tôi sẽ ngạc nhiên nếu đây là một thành tích đáng kể.
ephrion

4
Đánh giá this.statelà đầu vào this.setState(), thậm chí không thay đổi, không được khuyến khích. vui lòng xem câu trả lời của tôi ở trên để tham khảo tài liệu React chính thức về chủ đề này.
pscl

87

Bạn có thể sử dụng trình update()trợ giúp bất biến từreact-addons-update , điều này thực sự làm điều tương tự dưới mui xe, nhưng những gì bạn đang làm là tốt.

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

Ví dụ đơn giản hơn nhiều so với ví dụ bạn liên kết với :)
Koen.

7
react-addons-updatehiện không được chấp nhận (năm 2016). immutability-helpercó sẵn như là một thay thế. github.com/kolodny/immutability-helper Ngoài ra, vui lòng xem câu trả lời của tôi bên dưới về việc không làm thay đổi this.state trực tiếp bên trong this.setState ().
pscl

62

Tôi tin rằng việc tham khảo this.statebên trong setState()không được khuyến khích ( Cập nhật trạng thái có thể không đồng bộ ).

Các tài liệu khuyên bạn nên sử dụng setState()với chức năng gọi lại để tiền tố được truyền vào trong thời gian chạy khi cập nhật xảy ra. Vì vậy, đây là cách nó sẽ trông:

Sử dụng Array.prototype.filter không có ES6

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

Sử dụng Array.prototype.filter với Hàm mũi tên ES6

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

Sử dụng bất biến-helper

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

Sử dụng lây lan

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

Lưu ý rằng trong mỗi trường hợp, bất kể kỹ thuật được sử dụng, this.setState()đều được thông qua một cuộc gọi lại, không phải là một tham chiếu đối tượng đến cái cũ this.state;


3
Đây là câu trả lời đúng, xem thêm Sức mạnh của dữ liệu không đột biến
Vinnie James

1
Các ví dụ sử dụng hàm gọi lại trướcStState với các kỹ thuật khác nhau được thêm vào.
pscl

Nếu tôi làm nó như thế này thì sao? this.setState({ data: [...this.state.data.slice(0, index), ...this.state.data.slice(index + 1)] }); sử dụng this.statethay vì prevStatetùy chọn gọi lại được hiển thị bởi @ user1628461 phải không?
Tiberiu Maxim

Đây là giải pháp tốt nhất, mặc dù không đơn giản nhất
Developia

cảm ơn, bằng cách sử dụng lây lan có thể cập nhật một phần tử ở giữa thay vì xóa nó, đó là những gì tôi cần.
Vaibhav Vishal

24

Đây là một cách để loại bỏ phần tử khỏi mảng trong trạng thái bằng cách sử dụng cú pháp lây lan ES6.

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

1
Cảm ơn! Điều này cảm thấy như cách tự nhiên nhất để làm điều đó.
fabiomaia

3

Tôi muốn bấm chuông ở đây mặc dù câu hỏi này đã được trả lời chính xác bởi @pscl trong trường hợp có ai khác gặp phải vấn đề tương tự tôi đã làm. Trong số 4 phương pháp, tôi đã chọn sử dụng cú pháp es6 với các hàm mũi tên do tính đơn giản và thiếu phụ thuộc vào các thư viện bên ngoài:

Sử dụng Array.prototype.filter với Hàm mũi tên ES6

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

Như bạn có thể thấy tôi đã thực hiện một sửa đổi nhỏ để bỏ qua loại chỉ mục ( !==đến !=) bởi vì trong trường hợp của tôi, tôi đã lấy chỉ mục từ trường chuỗi.

Một điểm hữu ích khác nếu bạn thấy hành vi kỳ lạ khi xóa phần tử ở phía máy khách là KHÔNG BAO GIỜ sử dụng chỉ mục của một mảng làm khóa cho phần tử :

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

Khi React khác với DOM ảo khi thay đổi, nó sẽ xem xét các phím để xác định những gì đã thay đổi. Vì vậy, nếu bạn đang sử dụng các chỉ mục và có một ít hơn trong mảng, nó sẽ xóa cái cuối cùng. Thay vào đó, hãy sử dụng id của nội dung làm khóa, như thế này.

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

Trên đây là một đoạn trích từ câu trả lời này từ một bài liên quan .

Chúc mọi người mã hóa!


1

Bạn có thể sử dụng chức năng này, nếu bạn muốn loại bỏ phần tử (không có chỉ mục)

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

1

Như đã đề cập trong một nhận xét cho câu trả lời của ephrion ở trên, bộ lọc () có thể chậm, đặc biệt là với các mảng lớn, vì nó lặp để tìm kiếm một chỉ mục dường như đã được xác định. Đây là một giải pháp sạch, nhưng không hiệu quả.

Như một cách thay thế, người ta có thể chỉ cần 'cắt' phần tử mong muốn và ghép các mảnh.

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

Hi vọng điêu nay co ich!


0

Bạn có thể làm cho mã dễ đọc hơn với hàm trợ giúp một dòng:

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

sau đó sử dụng nó như vậy:

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

0

Chỉ là một gợi ý, trong mã của bạn thay vì sử dụng, let newData = prevState.databạn có thể sử dụng trải rộng được giới thiệu trong ES6 mà bạn có thể sử dụng let newData = ...prevState.data để sao chép mảng

Ba dấu chấm ... đại diện cho Toán tử trải rộng hoặc Tham số phần còn lại ,

Nó cho phép một biểu thức mảng hoặc chuỗi hoặc bất cứ thứ gì có thể lặp lại được mở rộng ở những nơi không có hoặc nhiều đối số cho các lệnh gọi hàm hoặc phần tử cho mảng được mong đợi.

Ngoài ra, bạn có thể xóa mục từ mảng với sau

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

Hy vọng điều này đóng góp !!


-3

Đây là một cách đơn giản để làm điều đó:

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

Hy vọng nó giúp!!!


Quan tâm để giải thích?
Tiberiu Maxim

5
Tôi nghĩ rằng đó là vì deletexóa mục nhưng chỉ mục không được cập nhật và do đó đây sẽ không phải là cách tiếp cận tốt cho nhu cầu thường xuyên.
Kunok
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.