如何在对象中传播嵌套属性?

IT技术 javascript reactjs object data-structures
2021-05-12 09:50:20

我在下面有这个对象。我想知道如何选择特定项目并更新属性。例如。项目 1 我想在数组中添加一个任务。

item: {
  'item-1': {
    id: 'item-1',
    title: 'To do',
    task: ['task-1', 'task-2', 'task-3', 'task-4']
  },
  'item-2': {
    id: 'item-2',
    title: 'In progress',
    task: []
  },

我目前有

const getItem = {...state.items['item-1']}
const newTaskList = [...getItem.task, newTask.id]

const newState = {
      ...state,
      items: {
        ...state.items,
        //How do I spread new array correctly in item 1?
        //...state.items['item-1'].task
      }
    };
3个回答

您需要使用对象键 ieitem-1并为其克隆属性并为任务键添加新列表。简而言之,在覆盖要更新的键之前,您需要在对象的每个级别进行克隆

const newState = {
  ...state,
  items: {
    ...state.items,
    'item-1': {
         ...state.items['item-1'],
         task: newTaskList
     }
  }
};

假设起点:

let state = {
    items: {
      'item-1': {
        id: 'item-1',
        title: 'To do',
        task: ['task-1', 'task-2', 'task-3', 'task-4']
      },
      'item-2': {
        id: 'item-2',
        title: 'In progress',
        task: []
      },
    }
};

如果您要添加到任务item-1task到位阵列,而无需修改的东西(这是很重要的阵营状态),你必须复制stateitemsitem-1,和item-1task

let newState = {
    ...state,
    items: {
        ...state.items,
        'item-1': {
            ...state.items['item-1'],
            task: [...state.items['item-1'].task, newTask]
        }
    }
};

现场示例:

在 lodadash 中,您可以从对象中获取和设置嵌套对象,这是我自己的实现:

//helper to get prop from object
const get = (object, path, defaultValue) => {
  const recur = (object, path) => {
    if (object === undefined) {
      return defaultValue;
    }
    if (path.length === 0) {
      return object;
    }
    return recur(object[path[0]], path.slice(1));
  };
  return recur(object, path);
};
//helper to set nested prop in object
const set = (
  state,
  statePath,
  modifier
) => {
  const recur = (result, path) => {
    const key = path[0];
    if (path.length === 0) {
      return modifier(get(state, statePath));
    }
    return Array.isArray(result)
      ? result.map((item, index) =>
          index === Number(key)
            ? recur(item, path.slice(1))
            : item
        )
      : {
          ...result,
          [key]: recur(result[key], path.slice(1)),
        };
  };
  const newState = recur(state, statePath);
  return get(state, statePath) === get(newState, statePath)
    ? state
    : newState;
};

let state = {
  items: {
    'item-1': {
      id: 'item-1',
      title: 'To do',
      task: ['task-1', 'task-2', 'task-3', 'task-4'],
    },
    'item-2': {
      id: 'item-2',
      title: 'In progress',
      task: [],
    },
  },
};
console.log(
  set(
    state,
    ['items','item-1','task'],
    (tasks)=>tasks.concat('new task')
  )
);

您可以将 get 和 set 放在一个库中,这将使您的代码的未来读者更容易设置深度嵌套的值。