구성 요소 상태의 배열에서 요소 제거


131

구성 요소 상태의 배열에서 요소를 제거하는 가장 좋은 방법을 찾으려고합니다. this.state변수를 직접 수정해서는 안되므로 배열에서 요소를 제거하는 더 나은 방법 (더 간결한 방법)이 있습니까?

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

감사합니다.

업데이트

setState에서 콜백을 사용하도록 업데이트되었습니다. 업데이트하는 동안 현재 상태를 참조 할 때 수행해야합니다.


React와 잘 작동하는 Facebook의 ImmutableJS를 살펴보십시오. 링크
Jonatan Lundqvist Medén

6
귀하의 코드에 문제가 없습니다. 실제로 그것은 관용적 인 방법입니다.
Dimitar Dimitrov

답변:


138

내가 본 가장 깨끗한 방법은 다음과 filter같습니다.

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

18
@HussienK _는 때때로 사용되지 않는 인수를 나타내는 데 사용됩니다. 여기, 배열의 현재 항목입니다.
chrisM

1
놀랄 만한. .filter를 항상 사용하고 있지만이 상황에서는 사용하지 않는 것이 좋습니다. : D
dakt

4
이것은 깨끗한 코드이지만 큰 배열의 경우이 방법이 느립니다. 이유는 전체 배열을 반복하여 이미 결정된 인덱스를 찾습니다.
매트 엘리스

1
@MattEllis 어쨌든 React의 상태 업데이트는 변경할 수 없으므로 목록 크기에 O (n)이 발생하여 언제든지 복사 할 수 있습니다. 이것이 중요한 성능 히트라면 놀랐습니다.
ephrion

4
에 대한 this.state입력으로 평가 하는 this.setState()것은 권장되지 않습니다. 이 주제에 대한 공식 React 문서에 대한 참조는 위의 답변을 참조하십시오.
pscl

87

에서 update()불변성 도우미를react-addons-update 사용할 수 있습니다 .

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

당신이 링크 한 것보다 훨씬 간단한 예 :)
Koen.

7
react-addons-update현재는 더 이상 사용되지 않습니다 (2016). immutability-helper대체품으로 제공됩니다. github.com/kolodny/immutability-helper 또한 this.setState () 내에서 this.state를 직접 변경하지 않는 것에 대한 아래 답변을 참조하십시오.
pscl

62

this.state내부 참조 setState()는 권장하지 않습니다 ( 상태 업데이트는 비동기 일 수 있음 ).

문서 setState()는 업데이트가 발생할 때 prevState가 런타임에 전달되도록 콜백 함수와 함께 사용 하는 것이 좋습니다 . 이것이 다음과 같이 보입니다 :

ES6없이 Array.prototype.filter 사용

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

ES6 화살표 함수와 함께 Array.prototype.filter 사용

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

불변 헬퍼 사용하기

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

스프레드 사용

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

사용 된 기술에 관계없이 각각의 경우 에 이전에 대한 객체 참조가 아닌this.setState() 콜백이 전달 된다는 점에 유의하십시오 .this.state



1
다양한 기술이 추가 된 prevState 콜백을 사용하는 예제.
pscl

내가 이렇게하면 어떡해? @ user1628461 에 표시된 콜백 옵션 대신 this.setState({ data: [...this.state.data.slice(0, index), ...this.state.data.slice(index + 1)] }); 사용 this.state하는 것이 잘못 prevState되었습니까?
Tiberiu Maxim

이것은 가장 간단하지는 않지만 최상의 솔루션입니다
Developia

덕분에 스프레드를 사용하여 요소를 삭제하는 대신 중간에 요소를 업데이트 할 수도 있습니다.
Vaibhav Vishal

24

다음은 ES6 스프레드 구문을 사용하여 상태의 배열에서 요소를 제거하는 방법입니다.

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

1
감사! 가장 자연스러운 방법 인 것 같습니다.
fabiomaia

3

이 질문 에 @pscl 이 이미 올바르게 대답 했지만 다른 사람이 내가 한 것과 같은 문제가 발생하는 경우를 대비 하여 여기에 차임하고 싶습니다 . 4 가지 방법 중 나는 간결하고 외부 라이브러리에 대한 의존성이 없기 때문에 화살표 함수와 함께 es6 구문을 사용하기로 선택했습니다.

ES6 화살표 함수와 함께 Array.prototype.filter 사용

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

보시다시피 , 필자의 경우 문자열 필드에서 색인을 검색했기 때문에 색인 유형 ( !==to !=) 을 무시하도록 약간 수정했습니다 .

클라이언트 측에서 요소를 제거 할 때 이상한 동작이 나타나는 경우 또 다른 유용한 점 은 배열의 색인을 요소의 키로 사용하지 않는 것입니다 .

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

React가 변경 사항에서 가상 DOM과 차이점을 변경하면 변경된 내용을 결정하는 키를 살펴 봅니다. 따라서 인덱스를 사용하고 있고 배열에 적은 것이 있으면 마지막 인덱스를 제거합니다. 대신 콘텐츠의 ID를 키로 사용하십시오.

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

위의 내용은 관련 게시물의 답변에서 발췌 한 것입니다 .

모두 행복한 코딩!


1

색인없이 요소를 제거하려는 경우이 기능을 사용할 수 있습니다.

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

1

위의 ephrion의 답변에 대한 언급에서 언급했듯이 filter ()는 이미 큰 것으로 판단되는 인덱스를 찾기 위해 반복되므로 특히 큰 배열의 경우 느릴 수 있습니다. 이것은 깨끗하지만 비효율적 인 솔루션입니다.

대안으로서, 원하는 요소를 간단히 '슬라이스'하고 단편들을 연결할 수있다.

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

도움이 되었기를 바랍니다!


0

한 줄 도우미 기능으로 코드를 더 읽기 쉽게 만들 수 있습니다.

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

다음과 같이 사용하십시오.

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

0

그냥 제안, 사용하는 대신 코드에서 let newData = prevState.data당신은 당신이 사용할 수있다 ES6에 도입 확산을 사용할 수 있습니다let newData = ...prevState.data 하여 배열을 복사

3 개의 점 ...은 스프레드 연산자 또는 나머지 매개 변수를 나타냅니다 .

배열 표현식이나 문자열 또는 반복 할 수있는 모든 것이 함수 호출 또는 배열 요소가 0 개 이상의 인수가 필요한 위치에서 확장 될 수 있습니다.

또한 다음을 사용하여 배열에서 항목을 삭제할 수 있습니다

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

이것이 기여하기를 바랍니다!


-3

간단한 방법은 다음과 같습니다.

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

도움이 되길 바랍니다 !!!


설명 할까?
Tiberiu Maxim

5
delete항목을 제거하지만 인덱스가 업데이트되지 않기 때문에 정기적 인 요구에 적합한 방법이 아니라고 생각합니다.
Kunok
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.