【问题标题】:Redux, "delete Object" is not working properly in nested ObjectRedux,“删除对象”在嵌套对象中无法正常工作
【发布时间】:2021-08-11 08:26:10
【问题描述】:

Redux,“删除对象”在嵌套对象中无法正常工作。我只是想删除键“0”中的键“b”。我只能删除键“0”,但是当我尝试删除“0”中的嵌套键“b”时,它不起作用。如果您知道如何解决它,请告诉我!

代码:

export function removeOrder(key1, key2) {
  return {
    type: 'REMOVE_ORDER',
    payload: {key1: key1, key2: key2},
  };
}

var initialState = {
  0: {
    a: {
      title: 'aa',
    },
    b: {
      title: 'bb',
    },
    c: {
      title: 'cc',
    },
  },

  1: {
    a: {
      title: 'aa',
    },
    b: {
      title: 'bb',
    },
    c: {
      title: 'cc',
    },
  },
};

function ordersReducer(state = initialState, action) {
  switch (action.type) {
    case 'REMOVE_ORDER':
      const id1 = action.payload.id1;
      const id2 = action.payload.id2;

      // Working
      //delete state[id1];

      // Not working
      delete state[id1][id2];

      return state;
    default:
      return state;
  }
}

removeOrder(0, 'a');

预期结果:

{
  0: {
    b: {
      title: 'bb',
    },
    c: {
      title: 'cc',
    },
  },

  1: {
    a: {
      title: 'aa',
    },
    b: {
      title: 'bb',
    },
    c: {
      title: 'cc',
    },
  },
};

【问题讨论】:

  • 一旦你有了delete state[id1],它就不能存在给你delete state[id1][id2] - 删除内部对象然后删除外部对象绝对没有意义,因为你正在删除外部对象反正
  • 我的意思是如果我只使用“delete state[id1][id2]”而不使用“delete state[id1]”,它不会删除嵌套对象。
  • 也许您的意思是const id1 = action.payload.key1; const id2 = action.payload.key2;,因为这就是动作对象的样子?或者可能是payload: {id1: key1, id2: key2},,因为这是函数所期望的?看起来像一个简单的错字 - 注意 delete obj[undefined] 不会抛出错误 - 这就是为什么 delete state[id1]; 没有抛出错误,即使它什么也没做

标签: javascript reactjs react-native redux


【解决方案1】:

你不能 delete 这样的状态字段,因为这会改变实际的 state 对象,这是 Redux 中的基本禁忌之一。从他们的文档中:

https://redux.js.org/usage/troubleshooting#never-mutate-reducer-arguments
修改 Redux 传递给您的状态或操作是很诱人的。不要这样做!

有关一般模式,请参阅immutable-update-patterns。特别是对于您的示例,您需要创建一个新的状态对象,传播您想要的值...一种简单的方法是使用 lodash 的 omitBy 排除具有您不想要的特定键的项目没有了。

function ordersReducer(state = initialState, action) {
  switch (action.type) {
    case 'REMOVE_ORDER':
      const id1 = action.payload.id1; 
      return omitBy(state, (value, key) => key === id1);
    default:
      return state;
  }
}

正如其他人在 cmets 中提到的,如果 id2 只是 id1 的子键,您可以忽略它。

如果您只想删除 id1 的子键,则可以改用它,这是对相同方法的轻微修改:

function ordersReducer(state = initialState, action) {
  switch (action.type) {
    case 'REMOVE_ORDER':
      const id1 = action.payload.id1; 
      const id2 = action.payload.id2;
      
      return {
          ...state,
          [id1]: omitBy(state, (value, key) => key === id2)
      };

    default:
      return state;
  }
}

【讨论】:

  • 我认为 OP 想要删除 key1.key2 甚至是嵌套更深的东西,因此需要递归删除。
  • @HMR 也许,这还不清楚。我将扩大我的答案以涵盖这一点:)
【解决方案2】:

你不应该改变状态,你可以使用spread你不需要为你的项目添加额外的依赖,省略几行代码:

function omit(state, keys) {
  const { [keys[0]]: remove, ...rest } = state;
  if (keys.length === 1) {
    return rest;
  }
  return {
    ...state,
    [keys[0]]: omit(remove, keys.slice(1)),
  };
}

//test code:
const state = {
  0: {
    b: {
      title: 'bb',
    },
    c: 'not changed',
  },

  1: 'not changed',
};
console.log('remove 0', omit(state, ['0']));
console.log('remove 0,b', omit(state, ['0', 'b']));
console.log(
  'remove 0,b,title',
  omit(state, ['0', 'b', 'title'])
);

【讨论】:

    【解决方案3】:

    正如 Bravo 指出的那样,一旦删除“根”属性,所有嵌套属性也会被删除。

    除了属性删除之外,您还有一个状态突变问题,因为您删除了一个属性然后返回相同的状态对象。

    您需要返回一个新的状态副本,然后您可以使用单个删除引用“完整”动态路径到第二个嵌套键。

    case 'REMOVE_ORDER':
      const { key1, key2 } = action.payload;
    
      // shallow copy state
      const nextState = { ...state };
    
      if (state[key1]) {
        // shallow copy the nested state
        nextState[key1] = { ...state[key1] }
      }
    
      // delete the nested property if it exists
      delete nextState[key1]?.[key2]; 
    
      return nextState;
    

    【讨论】:

    • 我认为 OP 想要删除 key1.key2 甚至是动态数量的键。一个解决方案可能是使其递归。
    • @HMR 向 OP 发表评论要求澄清垃圾邮件的其他答案可能会更有成效。 ?另外,我想我明白你的意思了。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-18
    • 2020-12-20
    • 2020-09-03
    • 1970-01-01
    • 1970-01-01
    • 2015-07-04
    • 2012-12-09
    相关资源
    最近更新 更多