Давайте теперь изучим реактивность массива объектов. Как правило, вы будете работать с такой структурой достаточно часто. Поэтому вам необходимо знать, как иммутабельно осуществлять добавление, изменение и удаление элементов такого массива.
Проблема здесь в том, что все изменения следует проводить по id, которые хранятся внутри самих объектов. Из-за этого нельзя просто взять и получить элемент по его id как по ключу массива.
Придется перебирать массив циклом и в цикле проверять каждый из объектов на то, равен ли его id тому, который нам нужен. Если равен, то выполним с ним нужную нам операцию, а если не равен - то оставим элемент без изменения.
Давайте посмотрим на примерах. Пусть у нас есть следующий массив объектов:
const initNotes = [
{
id: 'GYi9G_uC4gBF1e2SixDvu',
prop1: 'value11',
prop2: 'value12',
prop3: 'value13',
},
{
id: 'IWSpfBPSV3SXgRF87uO74',
prop1: 'value21',
prop2: 'value22',
prop3: 'value23',
},
{
id: 'JAmjRlfQT8rLTm5tG2m1L',
prop1: 'value31',
prop2: 'value32',
prop3: 'value33',
},
];
function App() {
}
Давайте выведем каждый элемент нашего массива в отдельном абзаце, а значения свойств каждого объекта - в своем span внутри абзаца:
function App() {
const [notes, setNotes] = useState(initNotes);
const result = notes.map(note => {
return <p key={note.id}>
<span>{note.prop1}</span>,
<span>{note.prop2}</span>,
<span>{note.prop3}</span>
</p>;
});
return <div>
{result}
</div>;
}
Удаление
Пусть в переменной хранится id элемента массива:
const id = 'IWSpfBPSV3SXgRF87uO74';
Давайте удалим элемент с таким id. Используем для этого метод filter:
setNotes(notes.filter(note => {
if (note.id !== id) {
return note;
}
}));
Код можно упростить:
setNotes(notes.filter(note => note.id !== id));
Пусть в переменной хранится id элемента. Сделайте кнопку, которая будет удалять элемент с заданным id.
Добавление
Пусть в переменной хранится объект, который мы хотим сделать новым элементом нашего массива:
const newElem = {
id: 'GMNCZnFT4rbBP6cirA0Ha',
prop1: 'value41',
prop2: 'value42',
prop3: 'value43',
};
Для этого можно добавить элемент в копию массива:
const copy = Object.assign([], notes);
copy.push(newElem);
setNotes(copy);
Либо воспользоваться деструтуризацией:
setNotes([...notes, newElem]);
Под абзацами сделайте кнопку, по нажатию на которую в наш массив будет добавляться новый элемент. Пусть при каждом нажатии на кнопку для добавляемого элемента генерируется новый id.
Изменение
Пусть мы хотим изменить какой-нибудь элемент массива. Пусть новые данные хранятся в переменной, например, вот такие:
const data = {
id: 'IWSpfBPSV3SXgRF87uO74',
prop1: 'value21 !',
prop2: 'value22 !',
prop3: 'value23 !',
};
В приведенном объекте id совпадает с id второго элемента массива, а значения свойств - другие. Говоря другими словами в data в свойстве id у нас хранится id того элемента массива, который мы хотим изменить.
Давайте выполним это изменение. Для этого будем перебирать элементы массива циклом и, если id совпадает с искомым, выполним замену элемента, а если не совпадает, оставим элемент без изменений:
setNotes(notes.map(note => {
if (note.id === data.id) {
return data;
} else {
return note;
}
}));
Можно сократить код, воспользовавшись тернарным оператором:
setNotes(notes.map(note => note.id === data.id ? data : note));
Сделайте кнопку, по нажатию на которую будет изменен элемент массива с id, равным 'JAmjRlfQT8rLTm5tG2m1L'.
Изменение одного свойства
Вам может потребоваться изменять не весь объект, а конкретное свойство. Давайте посмотрим, как это делается.
Пусть в переменных хранятся id элемента, имя свойства для изменения и новое значение свойства:
const id = 'IWSpfBPSV3SXgRF87uO74';
const prop = 'prop1';
const value = '!!!';
Для решения задачи удобно использовать деструктуризацию и вычисляемые имена свойств:
setNotes(notes.map(note => {
if (note.id === id) {
return {...note, [prop]: value};
} else {
return note;
}
}));
Даны следующие переменные:
const id = 'JAmjRlfQT8rLTm5tG2m1L';
const prop = 'prop2';
Сделайте кнопку, по нажатию на которую будет браться элемент массива с указанным id, в нем будет браться свойство с указанным именем и в конец значения этого свойства будет дописываться знак '!'.
Пусть даны две переменные с именами свойств:
const id = 'JAmjRlfQT8rLTm5tG2m1L';
const prop1 = 'prop2';
const prop2 = 'prop3';
Модифицируйте предыдущую задачу так, чтобы по клику изменения выполнялись сразу для двух указанных свойств.
Переделайте приведенное в теории решение через копирование объекта с помощью Object.assign.
Получение элемента
Вам может потребоваться получить элемент массива по его id. Давайте посмотрим, как это делается.
Пусть id элемента хранится в переменной:
const id = 'IWSpfBPSV3SXgRF87uO74';
Давайте получим элемент с таким id. Используем для этого метод reduce:
const result = notes.reduce((res, note) => {
if (note.id === id) {
return note;
} else {
return res;
}
}, {});
Код можно сократить:
const result = notes.reduce((res, note) => note.id === id ? note: res, {});
Получение значение свойства элемента
Вам может потребоваться получить элемент по id, а затем извлечь из этого элемента значение определенного свойства. Давайте посмотрим, как это делается.
Пусть id элемента и необходимое свойство хранятся в переменных:
const id = 'IWSpfBPSV3SXgRF87uO74';
const prop = 'prop1';
Для решения задачи нужно просто модифицировать полученный ранее код с reduce:
const result = notes.reduce((res, note) => {
if (note.id === id) {
return note[prop]; // получаем заданное свойство
} else {
return res;
}
}, '');
А вот сокращенный вариант:
const result = notes.reduce((res, note) => note.id === id ? note[prop] : res, '');
Даны следующие переменные:
const id = 'JAmjRlfQT8rLTm5tG2m1L';
const prop = 'prop2';
Сделайте кнопку, по нажатию на которую в какой-нибудь абзац из объекта с указанным id выведется значение свойства с указанным именем.
Следующие уроки
В следующих уроках мы будем разбирать реактивность массива объектов подробнее и посвятим отдельные уроки для разбора удаления, добавления, изменения массива объектов.
Для краткости я все примеры буду писать для массива initNotes из начала данного урока, а для всех задач я буду использовать следующий массив продуктов, в котором id() - созданная в предыдущем уроке функция для генерации id:
const initProds = [
{id: id(), name: 'prod1', catg: 'catg1', cost: 100},
{id: id(), name: 'prod2', catg: 'catg2', cost: 200},
{id: id(), name: 'prod3', catg: 'catg3', cost: 300},
];
Возьмите массив с продуктами initProds и выведите его в виде HTML таблицы. На основе этой таблицы решайте задачи следующих уроков.