用于更新具有不同嵌套深度的对象值的功能

时间:2019-04-24 01:50:40

标签: javascript reactjs

这可能是重复的,因为我认为这是常见的情况,但是我在Stack Overflow上找不到任何能回答我问题的东西。

我已经设置了一个保持初始状态的对象,如下所示(提取仅显示该问题的相关值):

export const initialState = {
  signUpDialog: {
    open: false,
    nameField: {
      isEmpty: false,
      isInvalid: false
  }
}

如您所见,open状态在signUpDialog下嵌套了1个深度,而isEmptyisInvalid则嵌套了2个深度。

我正在使用React Hooks来管理状态,并让以下操作创建者将值传递给我的状态减少器:

export const TOGGLE_BOOLEAN = "TOGGLE_BOOLEAN";
export function toggleBoolean(state, subState, value) {
  return {
    type: TOGGLE_BOOLEAN,
    payload: {
      state: state,
      subState: subState,
      value: value
    }
  };
}

以及以下更改状态的reducer(请注意:state参数等于当前状态,而action参数等于toggleBoolean操作创建者的返回值):

const reducer = (state, action) => {
  const reduced = { ...state };
  switch (action.type) {
    case TOGGLE_BOOLEAN:
      return Object.assign({}, state, {
        ...reduced,
        [action.payload.state]: {
          ...reduced[action.payload.state],
          [action.payload.subState]: action.payload.value
        }
      });
    default:
      state;
  }
};

这对于更新open状态非常有效,因为它仅嵌套在action.payload.state ='signUpForm'的1个深度,但是不适用于name: { isEmpty}name: { isInvalid }因为它们都嵌套在2深处。

我知道我可以通过创建不同的动作创建者并针对每个深度级别切换案例来解决此问题,但这并不是DRY,因为他们本质上是在做同一件事。

有没有更简单的DRY解决方案?

1 个答案:

答案 0 :(得分:1)

这是一个简单的代码草图。也许它将帮助您找到解决方案-

const setKV = (k, v) => (o = {}) =>
  ({ ...o, [k]: v })

const setDeepKV = (k, v, ...more) => (o = {}) =>
  more.length === 0
    ? setKV (k, v) (o)
    : setKV (k, setDeepKV (v, ...more) (o [k])) (o)

const print = (...vs) =>
  vs .forEach (v => console.log (v))

print
  ( setDeepKV ('a', 'X') ({})
  // { a: 'X' }
  
  , setDeepKV ('a', 'X') ({ a: 1, b: 2 })
  // { a: 'X', b: 2 }

  , setDeepKV ('a', 'a1', 'a2', 'X') ({ a: 1, b: 2 })
  // { a: { a1: { a2: 'X' } }, b: 2 }

  , setDeepKV ('a', 'b', 'c', 'X') ({ a: { b: { c: 1, d: 2 } }, e: 3 })
  // { a: { b: { c: 'X', d: 2 } }, e: 3 }

  , setDeepKV ('a', 'b', 'X') ({ a: { b: { c: 1, d: 2 } }, e: 3 })
  // { a: { b: 'X' }, e: 3 }
  )