Удаление элемента из массива состояний в реакции - PullRequest
1 голос
/ 11 марта 2020

У меня есть функция удаления, которая выглядит следующим образом:

   this.deleteItem = item => event => {
      const { res, selectedItems } = this.state;
      res.splice(res.indexOf(item), 1);
      selectedItems.splice(res.indexOf(item), 1);

      this.setState({
        res
      });
    };

Здесь res - это список элементов, отображаемых на странице, а selectedItems - это список этих элементов. выбраны. При удалении элемента из res необходимо обновить selectedItems, чтобы удалить индекс этого элемента из списка.

Однако всякий раз, когда я пытаюсь удалить указанный элемент c, он просто удаляет последний элемент, добавленный в массив, а не элемент, соответствующий индексу выбранной цели. Что-то должно происходить с тем, как это индексируется, но у меня были проблемы с определением источника.

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

Что было бы хорошим способом go по этому поводу?

Большое спасибо.

РЕДАКТИРОВАТЬ : Изменена функция, чтобы она выглядела как ответ @ HMK. После удаления элемента вывод console.log(res) в методе рендеринга представляет собой массив объектов, который имеет вид:

res 
(9) […]
​
0: Object { id: 0, name: "a", description: "description of a", … }
​
1: Object { id: 2, name: "b", description: "description of b", … }
​
2: Object { id: 3, name: "c", description: "description of c", … }
​
3: Object { id: 4, name: "d", description: "description of d", … }
​
4: Object { id: 5, name: "e", description: "description of e", … }
​
5: Object { id: 6, name: "f", description: "description of f", … }
​
6: Object { id: 7, name: "g", description: "description of g", … }
​
7: Object { id: 8, name: "h", description: "description of h", … }
​
8: Object { id: 9, name: "i", description: "description of i", … }
​
length: 9
​
<prototype>: Array []

Вывод console.log(JSON.stringify(item,undefined,2)); в функции deleteItem является объектом который удаляется из массива.

например:

{
  "id": 10,
  "name": "j",
  "description": "description of j",
  "icon": "jIcon",
  "selected": false
}

Когда выбраны все элементы на странице, вывод console.log("selecteditems:", JSON.stringify(selectedItems)):

selecteditems: [0,1,2,3,4,5,6,7,8,9,10]

1 Ответ

3 голосов
/ 11 марта 2020

Чтобы извлечь элемент из массива, вы можете сделать следующее:

array.filter(item=>item!==itemToRemove)

Итак, в вашем примере:

this.deleteItem = item => event => {
  const filter = getter => val => getter(val) !== item.id
  this.setState({
    res: this.state.res.filter(filter(({id})=>id)),
    selectedItems: this.state.selectedItems.filter(
      filter(id=>id)
    )
  })
}

Проблема в том, что res сохраняет массив объектов с идентификатором (например: [{id:1}], затем selectedItems является массивом, в котором хранится идентификатор: (например: [1]).

Array.prototype.filter работает следующим образом: newArray = array.filter(filterFunction). Для каждого элемента в массиве функция filterFunction вызывается с этим элементом. Если filterFunction возвращает false, то этот элемент не копируется в newArray, он возвращает значение true, если он копируется в newArray. Исходный массив остается неизменным (как это должно быть с состоянием, потому что вы не должны изменять его).

Так что проблема в том, что ваша функция фильтра получает элемент массива, решает, должен ли он возвращать true или false (true, чтобы сохранить элемент и false не сохранять). Так что, если я отфильтрую res, функция фильтра получит {id:X} (объект с идентификатором), но когда я отфильтрую selectedItems, я получу X ( id ) .

Так что фильтр функционирует Однако необходимо удалить элемент (ы) с определенным идентификатором; с res этот идентификатор является свойством объекта, а с selectedItems это идентификатор. Для res вы можете написать функцию получения, чтобы получить идентификатор объекта: resItem=>resItem.id, присвоить этой функции элемент из res, и он вернет идентификатор. Для selectedItems функция получения должна просто возвращать значение, которое она дала, потому что элементы в selectedItems являются идентификаторами, так что функция получения выглядит как id=>id

Хорошо, давайте вернемся для фильтрации у меня есть массив идентификаторов с именем selectedItems [9] и я хочу удалить идентификатор со значением 9, давайте назовем этот idToRemove, чтобы я мог сделать: selectedItems.filter(id=>id!==idToRemove). Эта же функция не будет работать с res, потому что {id:9} никогда не будет равняться 9.

Но что, если я передам селектор в функцию фильтра, здесь это немного усложняется, потому что функции могут возвращать функция:

const idToRemove = 9;
//filter function return true for array item to stay in the copied array
// and false to not include the array item in the copy
const filter = getter => arrayItem =>
  getter(arrayItem) !== idToRemove;
//passing filter a getter function will return a function that takes
//  an item and uses the getter function on that item to compare it
//  to idToRemove
const compareId = filter(id => id);
console.log('keep 9?', compareId(9));
console.log('keep 8?', compareId(8));
//now create a filter function that takes an object and uses
//  the getter to get object.id and compares that to idToRemove
const compareObjectWithId = filter(object => object.id);
console.log('keep {id:9}?', compareObjectWithId({ id: 9 }));
console.log('keep {id:8}?', compareObjectWithId({ id: 8 }));

Итак, compareId - это функция, которую мы можем использовать для фильтрации элемента из selectedItems, а compareObjectWithId - это функция, которую мы можем использовать для фильтрации элемента из res Вот как используется фильтр:

const idToRemove = 9;
const createFilterFunction = getter => arrayItem =>
  getter(arrayItem) !== idToRemove;
console.log(
  '[2,9] remove id 9',
  [2, 9].filter(createFilterFunction(id => id))
);
console.log(
  '[{id:2},{id:9}] remove id 9',
  [{ id: 2 }, { id: 9 }].filter(
    createFilterFunction(object => object.id)
  )
);

Для завершения я добавлю современный код для удаления ключа из объекта (не пытайтесь сделать это во фрагменте кода переполнения стека, поскольку он использует древнюю версию Babel)

const org = {a:1,b:2};
const withoutA = Object.fromEntries(
  Object.entries(org).filter(([key])=>key!=='a')//removed key 'a'
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...