이것이 redux를 사용하여 항목을 삭제하는 올바른 방법입니까?


116

입력을 변경해서는 안되며 개체를 복제하여 변경해야한다는 것을 알고 있습니다. 나는 redux 스타터 프로젝트에서 사용되는 규칙을 따르고 있었다.

ADD_ITEM: (state, action) => ({
  ...state,
  items: [...state.items, action.payload.value],
  lastUpdated: action.payload.date
})

항목을 추가하기 위해-스프레드를 사용하여 배열에 항목을 추가합니다.

내가 사용한 삭제 :

DELETE_ITEM: (state, action) => ({
  ...state,
  items: [...state.items.splice(0, action.payload), ...state.items.splice(1)],
  lastUpdated: Date.now() 
})

하지만 이것은 입력 상태 객체를 변경하고 있습니다-새 객체를 반환하더라도 이것이 금지되어 있습니까?


1
빠른 질문. Splice는 제거한 항목을 반환합니다. 그것이 당신의 의도입니까? 그렇지 않다면 슬라이스를 사용해야합니다.이 역시 무변이 법칙을 준수합니다.
m0meni

이 예제에서는 배열의 두 섹션을 새 배열로 연결합니다. 제거하려는 항목은 생략합니다. Slice는 제거 된 항목도 반환합니다. 원래 배열을 변경하지 않고 그렇게하는 것이 더 나은 접근 방식일까요?
CWright

귀하의 제안에 따라 @ AR7 : items: [...state.items.slice(0, action.payload.value), ...state.items.slice(action.payload.value + 1 )]입력을 변경하지 않도록 스플 라이스 대신 지금 슬라이스를 사용 하십시오 -이것이 갈 길입니까 아니면 더 간결한 방법이 있습니까?
CWright

답변:


207

아니요. 상태를 변경하지 마십시오.

새 객체를 반환하더라도, 절대 원하지 않는 이전 객체를 여전히 오염시키고 있습니다. 이것은 이전 상태와 새 상태를 비교할 때 문제가됩니다. 예를 들어 shouldComponentUpdatereact-redux가 내부적으로 사용하는 경우. 또한 시간 여행을 불가능하게 만듭니다 (예 : 실행 취소 및 다시 실행).

대신 변경 불가능한 방법을 사용하십시오. 항상 사용 Array#slice하고 절대 Array#splice.

귀하의 코드 action.payload에서 제거되는 항목의 색인 이라고 가정합니다 . 더 나은 방법은 다음과 같습니다.

items: [
    ...state.items.slice(0, action.payload),
    ...state.items.slice(action.payload + 1)
],

이것은 배열의 마지막 요소를 처리하는 경우 작동하지 않습니다. 또한 ...두 번째 문에서를 사용 하면 상태의 내용이 두 배가됩니다
Thaenor

4
jsfiddle / codepen 예제를 사용하여 증명하십시오. 스 니펫 arr.slice(arr.length)은의 내용에 관계없이 항상 빈 배열을 생성해야합니다 arr.
David L. Walsh

1
@ david-l-walsh 혼동을 드려 죄송합니다.이 예제를 테스트 할 때 오타 나 무언가를 만든 것 같습니다. 그것은 놀라운 일을합니다. 내 유일한 질문은 ...두 번째 부분에서 스프레드 연산자가 필요한 이유입니다....state.items.slice(action.payload + 1)
Thaenor

5
Array#slice배열을 반환합니다. 두 슬라이스를 단일 배열로 결합하기 위해 스프레드 연산자를 사용했습니다. 그것 없이는 배열의 배열을 갖게됩니다.
David L. Walsh

4
말이 되네요. 명확히 해주셔서 대단히 감사합니다 (그리고 처음에는 혼란스러워서 죄송합니다).
Thaenor

149

배열 필터 메서드를 사용하여 원래 상태를 변경하지 않고 배열에서 특정 요소를 제거 할 수 있습니다.

return state.filter(element => element !== action.payload);

코드 컨텍스트에서 다음과 같이 보일 것입니다.

DELETE_ITEM: (state, action) => ({
  ...state,
  items: state.items.filter(item => item !== action.payload),
  lastUpdated: Date.now() 
})

1
필터가 새 배열을 생성합니까?
chenop

6
@chenop 예, Array.filter 메서드는 새 배열을 반환합니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Steph M

4
중복 된 항목이 있으면 모두 제거됩니다. 필터를 사용하여 특정 색인을 제거하려면 다음을 사용할 수 있습니다.arr.filter((val, i) => i !== action.payload )
erich2k8

21

ES6 Array.prototype.filter메서드는 기준과 일치하는 항목이있는 새 배열을 반환합니다. 따라서 원래 질문의 맥락에서 이것은 다음과 같습니다.

DELETE_ITEM: (state, action) => ({
  ...state,
  items: state.items.filter(item => action.payload !== item),
  lastUpdated: Date.now() 
})

.filter()ES2015 방법은 아니지만 이전 버전 ES5에 추가되었습니다.
morkro

7

객체가있는 배열에 대한 변경 불가능한 "DELETED"감속기의 또 다른 변형 :

const index = state.map(item => item.name).indexOf(action.name);
const stateTemp = [
  ...state.slice(0, index),
  ...state.slice(index + 1)
];
return stateTemp;

0

황금률은 변경된 상태가 아니라 새로운 상태를 반환하는 것입니다. 작업 유형에 따라 감속기에 도달 할 때 다양한 형태로 상태 트리를 업데이트해야 할 수 있습니다.

이 시나리오에서는 상태 속성에서 항목을 제거하려고합니다.

이것은 Redux의 변경 불가능한 업데이트 (또는 데이터 수정) 패턴의 개념을 가져옵니다. 상태 트리에서 값을 직접 변경하지 않고 항상 복사본을 만들고 이전 값을 기반으로 새 값을 반환하기를 원하기 때문에 불변성이 핵심입니다.

다음은 중첩 된 개체를 삭제하는 방법의 예입니다.

// ducks/outfits (Parent)

// types
export const NAME = `@outfitsData`;
export const REMOVE_FILTER = `${NAME}/REMOVE_FILTER`;

// initialization
const initialState = {
  isInitiallyLoaded: false,
  outfits: ['Outfit.1', 'Outfit.2'],
  filters: {
    brand: [],
    colour: [],
  },
  error: '',
};

// action creators
export function removeFilter({ field, index }) {
  return {
    type: REMOVE_FILTER,
    field,
    index,
  };
}

export default function reducer(state = initialState, action = {}) {
  sswitch (action.type) {  
  case REMOVE_FILTER:
  return {
    ...state,
    filters: {
    ...state.filters,
       [action.field]: [...state.filters[action.field]]
       .filter((x, index) => index !== action.index)
    },
  };
  default:
     return state;
  }
}

이를 더 잘 이해하려면 https://medium.com/better-programming/deleting-an-item-in-a-nested-redux-state-3de0cb3943da 기사를 확인하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.