如何将对象属性添加到状态中的另一个属性?

时间:2017-03-07 22:04:19

标签: javascript reactjs ecmascript-6 redux

我在react-redux应用中设置动作和缩减器。我需要一个函数来更新状态中的属性并将对象添加到其列表中,如果可能的话,使用扩展语法。这是我到目前为止所做的:

const defaultState = {
  genres: {}
}

export default function(state = defaultState, action) {
  switch(action.type) {
    case 'ADD_GENRE':
      return {
        ...state,
        genres[action.name]: action.list //new code here
      }
    default:
      return state;
  }
}

我需要动态访问genres属性,就像使用其属性名称的数组一样:

const getMusicFromGenre = (genre) => {
  return state.genres[genre];
}

reducer应接受以下操作,然后相应地修改状态:

// action
{
  type: 'ADD_GENRE,
  name: 'Rock',
  list: ['Bohemian Rhapsody', 'Stairway to Heaven', 'Hotel California']
}

// old state
{
  genres: {
    "Pop": ['Billie Jean', 'Uptown Funk, 'Hey Jude']
  }
}

// new state
{
  genres: {
    "Pop": ['Billie Jean', 'Uptown Funk, 'Hey Jude'],
    "Rock": ['Bohemian Rhapsody', 'Stairway to Heaven', 'Hotel California']
  }
}

如果有必要,我愿意采用不同的方法。

2 个答案:

答案 0 :(得分:3)

您已走上正轨,但需要分别处理每个级别的嵌套。这是我为http://redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html撰写的一个例子:

function updateVeryNestedField(state, action) {
    return {
        ....state,
        first : {
            ...state.first,
            second : {
                ...state.first.second,
                [action.someId] : {
                    ...state.first.second[action.someId],
                    fourth : action.someValue
                }
            }
        }
    }
}

您可能还想阅读我在http://redux.js.org/docs/recipes/reducers/PrerequisiteConcepts.html#immutable-data-managementhttps://github.com/markerikson/react-redux-links/blob/master/immutable-data.md链接的一些有关不可变数据处理的文章。

答案 1 :(得分:2)

immutability-helper是一个非常有用的库,用于执行状态更新。在您的情况下,它将像这样使用,如果没有现有项目,将创建一个新数组,或者如果存在预先存在的项目,则使用操作列表连接现有项目:

import update from 'immutability-helper';

const defaultState = {
  genres: {}
}

const createOrUpdateList = (prev, list) => {
   if (!Array.isArray(prev)) {
       return list;
   }
   return prev.concat(list);
   // or return [...prev, ...list] if you prefer
}

export default function(state = defaultState, action) {
  switch(action.type) {
    case 'ADD_GENRE':
      return update(state, {
          genres: {
              [action.name]: {
                  $apply: prev => createOrUpdate(prev, action.list)
              }
          }
      });
    default:
      return state;
  }
}