【问题标题】:How to update Nested Array with useReducer?如何使用 useReducer 更新嵌套数组?
【发布时间】:2021-08-08 22:26:12
【问题描述】:

我有这些:

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 不支持未定义。完全错误:

类型 '{ [x: number]: { 选中: boolean |不明确的; };长度?: 号码 |不明确的; 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]

但我得到了

对象可能未定义

【问题讨论】:

    标签: javascript reactjs typescript


    【解决方案1】:

    您似乎错误地传播了新对象。您的 .map((item) =&gt; ...) 返回一个对象,但在其中您传播了一个(潜在的)数组,该数组只会填充数字(好吧,字符串化版本)键。您可能打算从item 复制原始字段,例如idtitle,并将映射的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
        })),
    );
    

    【讨论】:

    • 嗯,你似乎在这里有所作为。我更新了这个问题,因为我意识到我正在发送整个对象,所以我需要检查有效负载对象是否有子项,然后在状态上找到子项并更新它: newArrayChildCheck = state.items.map((item) = > ({ ...item, subItems: item.subItems?.map((sub, index) => ({ ...sub, checked: sub.id === payload.subItems[index]?.id ? true : sub.checked })),但不能让它工作。
    • 我在问题上添加了编辑
    • 我不知道payload.subItems 是什么,但显然它可以是undefined。此外,如果您使用 index 进行索引,那只是一个数字,您必须确保您的 item.subItemspayload.subItems 具有相同的项目以相同的顺序。
    • 好吧,这让我意识到我的结构有点不对劲。将接受答案,因为它给了我许可。谢谢!
    猜你喜欢
    • 2021-12-30
    • 2019-06-08
    • 2020-10-09
    • 2018-10-22
    • 2016-05-03
    相关资源
    最近更新 更多