Redux将对象嵌套为状态 - 这是可能的/最佳的

时间:2016-02-05 16:00:41

标签: reactjs redux

我是Redux的新手所以请耐心等待。我想知道以下是否可能和/或最佳,如果是这样,你如何更新reducer中的嵌套对象值?

const initialState = {
  banner: {
    backgroundColor: 'black',
    text: 'Some Title',
    textColor: 'white',
    image: null
  },
  nav: {
    mainOpen: false,
    authOpen: false,
  }

  ...
}

然后在减速器中这样的东西似乎不起作用......

export default function reducer(state = initialState, action = {}) {
  const {type, data} = action;
  switch (type) {
    case SET_BANNER_TEXT:
      return {
        ...state,
        banner.text: data //<-- ****THIS FAILS WITH UNEXPECTED TOKEN!!!****
      }

    ...
}

或者更好的是拥有一条横幅&#39;减速机,&#39; nav&#39;减速机等等?

TIA!

2 个答案:

答案 0 :(得分:2)

我对redux也有点新意,所以我不能说'最佳实践'。我会亲自倾向于一个新的reducer,因为你有像SET_BANNER_TEXT(color,img等?)这样的特定动作来修改你的状态树的特定部分,而不是别的。通过将它们分开来简化它们(即使它们有很多),将使你的减速器更容易追踪。

从语法上讲,你可以通过以下方式实现你想要做的事情:

export default function reducer(state = initialState, action = {}) {
  const {type, data} = action;
  switch (type) {
    case SET_BANNER_TEXT:
      const newBannerState = Object.assign({}, state.banner, {text: data});
      return Object.assign({}, state, {banner: newBannerState});
}

答案 1 :(得分:1)

由于您正在更新对象的密钥,请尝试使用此更新密钥

const state = {
  ...initialState,
  banner: {
    ...initialState.banner, // extend
    text: 'newText'
  }
}

转换为

var state = _extends({}, initialState, {
    banner: _extends({}, initialState.banner, {
        text: 'newText'
    })
});
ES5中的

检查此jsbin

编辑,如下面的评论中所述,如果上面使用了代码,它将覆盖整个横幅广告对象。您可以使用Object.assign()在此线程中尝试其他答案并克隆banner对象。如果您仍想使用传播操作符,我更新了我的答案。

我认为为深度嵌套状态设置特定的reducers也更好。我会写这样的东西

export function rootReducer(state = initialState, action) {
    switch (action.type) {
    case SET_BANNER_TEXT:
    case SET_BANNER_BG:
        return Object.assign({}, state,
            {
                banner: bannerReducer(state.banner, action)
            }
        );
    // ...
    default:
        return state;
    }
}

function bannerReducer(state, action) {
    switch (action.type) {
    case SET_BANNER_TEXT:
        return Object.assign({}, state, {text: action.payload});
    case SET_BANNER_BG:
        return Object.assign({}, state, {backgroundColor: action.payload});
    // ...
    default:
        return state;
    }
}