Функция для обновления значений объекта с разной глубиной вложенности

#javascript #reactjs

#javascript #reactjs

Вопрос:

Это может быть дубликат, поскольку я считаю, что это обычная ситуация, но я не могу найти в Stack Overflow ничего, что отвечало бы на мой вопрос.

Я установил объект, который содержит мое начальное состояние следующим образом (извлеките, чтобы показать только соответствующие значения для этого вопроса):

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

Как вы можете видеть, open состояние вложено на 1 глубину в signUpDialog, однако isEmpty и isInvalid вложено на 2 глубины.

Я использую перехватчики реакции для управления состоянием, и у меня есть создатель следующего действия для передачи значений в мой редуктор состояния:

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

И следующий редуктор, который изменяет состояние (примечание: 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 состояния, поскольку оно вложено только на 1 глубину при действии.payload.state=’signUpForm’, однако это не будет работать для name: { isEmpty} или name: { isInvalid } , поскольку они оба вложены на 2 глубины.

Я знаю, что мог бы решить эту проблему, используя разных создателей действий и переключая случаи для каждого уровня глубины, однако это не было бы СУХИМ, поскольку они, по сути, делают одно и то же.

Есть ли какие-либо более простые СУХИЕ решения для этого?

Ответ №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 }
  )  

Комментарии:

1. Спасибо, мне удалось заставить его работать, используйте это в качестве примера. Я отредактирую свой пост, чтобы включить в него свое решение.