Как обновить вложенный массив с помощью useReducer?

avatar
CodingLittle
8 августа 2021 в 22:26
173
1
2

У меня есть:

export type DataItemChild = {
  id: number;
  title:string;
  checked?: boolean;
};

Обратите внимание, что подэлементы здесь могут быть неопределенными:

export type DataItems = {
  id: number;
  title:string;
  subItems?: Array<DataItemChild>;
  checked?: boolean;
};

export const initalState: StateType = {
  items: [],
  date: new Date(),
};

До сих пор я выяснил, как обновить массив на объекте верхнего уровня, например:

  case ActionKind.Checked:
    newArrayChecked = state.items.map((item) => ({
      ...item,
      checked: item.id === payload.id ? true : item.checked,
    }));
    return {
      ...state,
      items: newArrayChecked,
    };

Не могу понять, как обновить подпункты? у меня есть это (урезанное)

export const reducer = (state: StateType, action: Action) => {
  const { type, payload } = action;
  let newArrayChildCheck: Array<DataItemChild> = []
  switch (type) {

    case ActionKind.UnCheckedSub:
      newArrayChildCheck = state.items.map((item) => ({
        ...item.subItems?.map((sub, index) => ({
          checked:  sub.id === payload.subItems?[index].id ? true: sub.checked
        })),
      }));
      return {
        ...state,
        items.subItems: newArrayChildCheck,
      };

    default:
      return state;
  }
};

Но это дает мне типическую ошибку, говорящую о том, что мой newArrayChildCheck не поддерживает undefined. Полная ошибка:

Введите '{ [x: число]: { проверено: логическое значение | неопределенный; }; длина?: номер | неопределенный; toString?: (() => строка) | неопределенный; toLocaleString?: (() => строка) | неопределенный; поп?: (() => { проверено: логический | неопределенный; } | не определено) | неопределенный; ...еще 29...; [Symbol.unscopables]?: (() => { ...; }) | неопределенный; }[]' не является назначаемый для типа «DataItemChild []». Введите '{ [x: число]: { проверено: логическое значение | неопределенный; }; длина?: число | неопределенный; toString?: (() => строка) | неопределенный; toLocaleString?: (() => строка) | неопределенный; поп?: (() =

РЕДАКТИРОВАТЬ:

после ответа @Kelvin Schoofs я понял, что отправляю целый объект, который имеет свои подэлементы. полезная нагрузка имеет тип DataItems

Я изменил свою попытку в соответствии с предложением @Kelvin Schoofs с небольшим изменением:

  newArrayChildCheck = state.items.map((item) => ({
    ...item,
    subItems: item.subItems?.map((sub, index) => ({
        ...sub,
        checked: sub.id === payload.subItems[index].id ? true : sub.checked
    })),

Не [index]

Но я получаю

объект возможно не определен

Источник

Ответы (1)

avatar
Kelvin Schoofs
8 августа 2021 в 22:32
2

Похоже, вы неправильно распределяете новый объект. Ваш .map((item) => ...) возвращает объект, но в нем вы выкладываете (потенциальный) массив, который будет заполнять только числовые (ну, строковые варианты) ключи. Вероятно, вы хотели скопировать исходные поля из item, такие как id и title, и назначить сопоставленный результат subItems полю subItems. То же самое для объекта, который вы создаете в своем subItems?.map. Что-то вроде этого является правильным типом:

newArrayChildCheck = state.items.map((item) => ({
    ...item,
    subItems: item.subItems?.map((sub) => ({
        ...sub,
        checked: sub.id === payload.id ? true : sub.checked
    })),
}));

Это если вам нужна измененная версия вашего массива DataItems. Если вы действительно хотите вернуть каждый DataItemChild с измененной версией checked, вы можете использовать flatMap следующим образом:

newArrayChildCheck = state.items.flatMap((item) => 
    item.subItems?.map((sub) => ({
        ...sub,
        checked: sub.id === payload.id ? true : sub.checked
    })),
);
CodingLittle
8 августа 2021 в 22:41
0

хм, вы, кажется, что-то здесь. Я немного обновляю вопрос, так как понял, что отправляю весь объект, поэтому мне нужно проверить, есть ли в объекте полезной нагрузки подэлементы, а затем найти подэлемент в состоянии и обновить его: newArrayChildCheck = state.items.map((item) = > ({ ...item, subItems: item.subItems?.map((sub, index) => ({ ...sub, checked: sub.id === payload.subItems[index]?.id ? true : sub.checked })), но не могу заставить его работать.

CodingLittle
8 августа 2021 в 22:48
0

Я добавил редактирование в вопрос

Kelvin Schoofs
8 августа 2021 в 22:54
0

Я не знаю, что такое payload.subItems, но, видимо, это может быть undefined. Кроме того, если вы индексируете, используя index, это просто число, вам нужно убедиться, что ваши item.subItems и payload.subItems имеют одинаковые элементы в том же порядке.

CodingLittle
8 августа 2021 в 23:05
0

Хорошо, это заставило меня понять, что моя структура немного неверна. Приму ответ, так как он дал мне разрешение. Спасибо!