Redux 嵌套对象作为状态 - 这是 possible/optimal

Redux nested objects as state - is this possible/optimal

我是 Redux 的新手,所以请多多包涵。我想知道是否有可能像下面这样的东西 and/or 是最优的,如果是这样,你如何更新 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!!!****
      }

    ...
}

还是有一个'banner'减速器,一个'nav'减速器等等更好?

TIA!

由于您正在更新对象的键,请尝试使用它来更新键

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

转换为

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

在 ES5 中

检查这个 jsbin

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

我认为对于深度嵌套有特定的减速器也更好state.And我会这样写

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

我对 redux 也有点陌生,所以我不能和 'best practice' 说太多。我个人倾向于使用新的 reducer,因为您有特定的操作,例如 SET_BANNER_TEXT(颜色、img 等?)修改状态树的特定部分,仅此而已。通过将 reducer 分开(即使它们有很多)来使你的 reducer 变得简单,将使事情更容易追踪。

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

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