Как удалить элемент из массива, который находится внутри объекта в React JS (ES6)

#javascript #arrays #reactjs #filter

#javascript #массивы #reactjs #Фильтр

Вопрос:

Я хотел бы удалить элемент из массива, который находится внутри объекта, и переопределить этот объект новыми значениями. Смотрите пример ниже.

 var obj = {
  a: [1, 2, 3],
  b: [4, 5, 6],
  c: [7, 8, 9]
}
 

Я хотел бы удалить число 5, obj не зная, в каком массиве находится элемент.

Я пытаюсь обновить состояние в react с помощью Context API. Он должен непосредственно возвращать сам объект.

 case ACTION: return {
  ...state,
  obj: ?
}
 

Ожидаемый конечный результат :

 var obj = {
  a: [1, 2, 3],
  b: [4, 6],
  c: [7, 8, 9]
}
 

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

1. Вы отметили это react , используете ли вы это с помощью state ? Если это так, ответ будет другим, поскольку вы не хотите напрямую изменять массив.

2. Да, я использую его react внутри контекста

Ответ №1:

Чтобы сгенерировать новый объект с обновленными значениями, вы можете использовать Object.entries() для преобразования объекта в записи [ключ, значение] . Сопоставьте записи и отфильтруйте массив значений, а затем преобразуйте записи обратно в объект с помощью Object.fromEntries() :

 const fn = (obj, item) =>
  Object.fromEntries(
    Object.entries(obj)
      .map(([k, v]) => [k, v.filter(o => o !== item)])
  )

const obj = {
  a: [1, 2, 3],
  b: [4, 6],
  c: [7, 8, 9]
}

const result = fn(obj, 5)

console.log(result) 

Здесь есть небольшая проблема, которая может привести к ненужному отображению — поскольку мы фильтруем все массивы, каждый массив является новым, даже если элемент изначально не существует в этом массиве. Мы можем решить эту проблему, проверив, действительно ли массив содержит элемент, прежде чем фильтровать его. Это может быть преждевременной оптимизацией, и ее следует профилировать.

 const fn = (obj, item) =>
  Object.fromEntries(
    Object.entries(obj)
      .map(e => e[1].includes(item) ? [e[0], e[1].filter(o => o !== item)] : e)
  )

const obj = {
  a: [1, 2, 3],
  b: [4, 6],
  c: [7, 8, 9]
}

const result = fn(obj, 5)

console.log(result.c === obj.c) // c didn't change

console.log(result) 

Если Object.fromEntries() он не поддерживается вашей средой, вы можете легко заменить его функцией, основанной на Array.reduce() :

 const fromEntries = entries =>
  entries.reduce((obj, [k, v]) => {
    obj[k] = v
  
    return obj
  }, {})

const fn = (obj, item) =>
  fromEntries(
    Object.entries(obj)
      .map(([k, v]) => [k, v.filter(o => o !== item)])
  )

const obj = {
  a: [1, 2, 3],
  b: [4, 6],
  c: [7, 8, 9]
}

const result = fn(obj, 5)

console.log(result) 

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

1. Это именно то, что я искал. Я запустил это vanilla js, но нормально ли, что в reactjs произошла ошибка undefined is not a function near Object.fromEntries ?

2. Object.fromEntries() поддерживается всеми новыми браузерами. Он не поддерживается IE.

3. Его легко Object.fromEntries() заменить функцией, основанной на reduce . Я добавлю пример.

Ответ №2:

Самый простой подход, ИМХО, был бы к splice этому массиву:

 obj.b.splice(1, 1);
 

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

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

 const toRemove = 5;
Object.keys(obj).forEach(k => {
    obj[k] = obj[k].filter(i => i != toRemove);
});
 

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

1. Как я уже сказал @plichard, это моя вина, я оговорился. Я скорее хотел удалить элемент, введенный пользователем, не зная, где находится этот элемент

2. @CustyZ01 итак, я неправильно понял их вопрос. Смотрите мой отредактированный ответ.

3. Спасибо за ваш ответ, но возвращает ли это объект? Например, могу ли я сделать это: obj = Object.keys(obj).forEach(k => { obj[k] = obj[k].filter(i => i != toRemove); }); я пытаюсь вернуть объект для обновления состояния реакции (см. Редактирование в вопросе)

4. @CustyZ01 это обновление obj на месте. Если вы хотите, вы можете затем вернуть его.

5. Вероятно, вы могли бы сделать obj.b.splice(obj.b.indexOf(5), 1)