Давайте теперь изучим реактивность массива объектов. Как правило, вы будете работать с такой структурой достаточно часто. Поэтому вам необходимо знать, как иммутабельно осуществлять добавление, изменение и удаление элементов такого массива.
Проблема здесь в том, что все изменения следует
проводить по 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 таблицы. На основе
этой таблицы решайте задачи следующих уроков.