[javascript] redux에서 특정 배열 항목 내부의 단일 값을 업데이트하는 방법

상태를 다시 렌더링하면 UI 문제가 발생하고 페이지에서 다시 렌더링되는 양을 줄이기 위해 내 감속기 내부의 특정 값만 업데이트하도록 제안 된 문제가 있습니다.

이것은 내 상태의 예입니다

{
 name: "some name",
 subtitle: "some subtitle",
 contents: [
   {title: "some title", text: "some text"},
   {title: "some other title", text: "some other text"}
 ]
}

그리고 나는 현재 이것을 이렇게 업데이트하고 있습니다

case 'SOME_ACTION':
   return { ...state, contents: action.payload }

여기서 action.payload새로운 값을 포함하는 전체 어레이이다. 하지만 이제 실제로 내용 배열에서 두 번째 항목의 텍스트를 업데이트해야하는데 이와 같은 것이 작동하지 않습니다.

case 'SOME_ACTION':
   return { ...state, contents[1].text: action.payload }

action.payload지금 업데이트가 필요한 텍스트는 어디에 있습니까 ?



답변

React Immutability 도우미를 사용할 수 있습니다.

import update from 'react-addons-update';

// ...    

case 'SOME_ACTION':
  return update(state, {
    contents: {
      1: {
        text: {$set: action.payload}
      }
    }
  });

아마 당신이 이런 일을 더 많이 할 거라고 생각하지만?

case 'SOME_ACTION':
  return update(state, {
    contents: {
      [action.id]: {
        text: {$set: action.payload}
      }
    }
  });


답변

사용할 수 있습니다 map. 다음은 구현의 예입니다.

case 'SOME_ACTION':
   return {
       ...state,
       contents: state.contents.map(
           (content, i) => i === 1 ? {...content, text: action.payload}
                                   : content
       )
    }


답변

한 줄로 모든 작업을 수행 할 필요는 없습니다.

case 'SOME_ACTION':
  const newState = { ...state };
  newState.contents =
    [
      newState.contents[0],
      {title: newState.contnets[1].title, text: action.payload}
    ];
  return newState


답변

파티에 매우 늦었지만 여기에 모든 인덱스 값과 함께 작동하는 일반적인 솔루션이 있습니다.

  1. 이전 어레이 index에서 변경하려는 어레이까지 새 어레이를 만들고 확산 합니다.

  2. 원하는 데이터를 추가하십시오.

  3. index변경하려는 어레이의 끝 에서 새 어레이를 만들고 확산

let index=1;// probabbly action.payload.id
case 'SOME_ACTION':
   return {
       ...state,
       contents: [
          ...state.contents.slice(0,index),
          {title: "some other title", text: "some other text"},
         ...state.contents.slice(index+1)
         ]
    }

최신 정보:

코드를 단순화하기 위해 작은 모듈을 만들었으므로 함수를 호출하기 만하면됩니다.

case 'SOME_ACTION':
   return {
       ...state,
       contents: insertIntoArray(state.contents,index, {title: "some title", text: "some text"})
    }

더 많은 예를 보려면 저장소를 살펴보십시오.

기능 서명 :

insertIntoArray(originalArray,insertionIndex,newData)


답변

Redux 상태 에서 이런 종류의 작업이 필요할 때 스프레드 연산자가 친구 이며이 원칙은 모든 어린이에게 적용됩니다.

이것이 당신의 상태라고 가정합시다.

const state = {
    houses: {
        gryffindor: {
          points: 15
        },
        ravenclaw: {
          points: 18
        },
        hufflepuff: {
          points: 7
        },
        slytherin: {
          points: 5
        }
    }
}

그리고 Ravenclaw에 3 점을 추가하고 싶습니다.

const key = "ravenclaw";
  return {
    ...state, // copy state
    houses: {
      ...state.houses, // copy houses
      [key]: {  // update one specific house (using Computed Property syntax)
        ...state.houses[key],  // copy that specific house's properties
        points: state.houses[key].points + 3   // update its `points` property
      }
    }
  }

스프레드 연산자를 사용하면 나머지는 그대로두고 새 상태 만 업데이트 할 수 있습니다.

놀라운 기사 에서 가져온 예제 , 훌륭한 예제와 함께 가능한 거의 모든 옵션을 찾을 수 있습니다.


답변

제 경우에는 Luis의 대답에 따라 다음과 같이했습니다.

...State object...
userInfo = {
name: '...',
...
}

...Reducer's code...
case CHANGED_INFO:
return {
  ...state,
  userInfo: {
    ...state.userInfo,
    // I'm sending the arguments like this: changeInfo({ id: e.target.id, value: e.target.value }) and use them as below in reducer!
    [action.data.id]: action.data.value,
  },
};


답변

이것이 내 프로젝트 중 하나를 위해 한 방법입니다.

const markdownSaveActionCreator = (newMarkdownLocation, newMarkdownToSave) => ({
  type: MARKDOWN_SAVE,
  saveLocation: newMarkdownLocation,
  savedMarkdownInLocation: newMarkdownToSave
});

const markdownSaveReducer = (state = MARKDOWN_SAVED_ARRAY_DEFAULT, action) => {
  let objTemp = {
    saveLocation: action.saveLocation,
    savedMarkdownInLocation: action.savedMarkdownInLocation
  };

  switch(action.type) {
    case MARKDOWN_SAVE:
      return(
        state.map(i => {
          if (i.saveLocation === objTemp.saveLocation) {
            return Object.assign({}, i, objTemp);
          }
          return i;
        })
      );
    default:
      return state;
  }
};