Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос нашим менторам. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Неизменяемость

Неизменяемость состояния - одна из ключевых тем в React. Её легко придерживаться, работая с примитивными типами данных, но с составными, такими как объекты и массивы, у неподготовленного пользователя могут возникнуть сложности. В этом уроке мы пробежимся по основным способам частичного обновления объектов и массивов.

Кроме примеров на чистом JS, я буду демонстрировать примеры с использованием библиотеки immutability-helper, которая создана для облегчения выполнения подобных операций. Она особенно актуальна при выполнении обновлений там, где код на JS получается слишком сложным.

Массивы

Массив: добавление

Самое простое, это добавление в массив:

const items = ['one', 'two', 'three'];
const item = 'four';
const newItems = [...items, item];
// ['one', 'two', 'three', 'four'];

Если необходимо добавить элемент в начало, то нужно всего лишь поменять местами элементы массива:

const newItems = [item, ...items];
// ['four', 'one', 'two', 'three'];
Использование immutability-helper
import update from 'immutability-helper';

const state1 = ['x'];
const state2 = update(state1, { $push: ['y'] }); // ['x', 'y']

Массив: удаление

Более интересный пример. Чтобы успешно выполнить удаление, нужно знать, что удалять. Это значит, что каждый элемент в коллекции должен иметь идентификатор. Для удаления используется старая добрая фильтрация.

const newItems = items.filter(item => item.id !== id);

Может возникнуть вопрос: откуда взялся идентификатор внутри обработчика? И здесь нам на помощь приходят замыкания.

See the Pen js_react_immutability_array_remove_element by Hexlet (@hexlet) on CodePen.

Обратите внимание на способ задания обработчика: removeItem = (id) => (e) => { и его использование onClick={this.removeItem(id)}.

Использование immutability-helper
const index = 5;
const newItems = update(items, {$splice: [[index, 1]]});

Удаление на чистом JS через фильтр - самый оптимальный способ. С использованием immutability-helper получается сложно.

Массив: изменение

К сожалению, без дополнительных инструментов код решения будет слишком громоздким. Я приведу его ниже для ознакомления, но в реальном коде так делать не надо.

const index = items.findIndex((item) => item.id === id);
const newItem = { ...items[index], value: 'another value' };
const newItems = [...items.slice(0, index), newItem, ...items.slice(index + 1)];

Думаю, мне не придётся вас убеждать в том, что это перебор :)

Использование immutability-helper
const collection = { children: ['zero', 'one', 'two'] };
const index = 1;
const newCollection = update(collection, { children: { [index]: { $set: 1 } } });
// { children: ['zero', 1, 'two'] }

Как видно, этот способ значительно проще и чище. Рекомендуется к использованию.

Объекты

Объект: добавление

Так же просто, как и с массивом.

const items = { a: 1, b: 2 };
const newItems = { ...items, c: 3 };
// { a: 1, b: 2, c: 3 }

Либо, если ключ вычисляется динамически, нужно делать так:

const items = { a: 1, b: 2 };
const key = 'c';
const newItems = { ...items, [key]: 3 };
// { a: 1, b: 2, c: 3 }

Объект: удаление

Решение ниже привожу только для ознакомления. На чистом JS нет простого способа удалить ключ в неизменяемом стиле:

Object.keys(myObj)
  .filter(key => key !== deleteKey)
  .reduce((acc, current) => ({ ...acc, [current]: myObj[current] }), {});
Использование immutability-helper
import update from 'immutability-helper';

const state = { a: 1, c: 3 };
const updatedState = update(state, {
  $unset: ['c'],
});
// { a: 1 }

Объект: изменение

Абсолютно то же самое, что и добавление.

const items = { a: 1, b: 2 };
const newItems = { ...items, a: 3 };
// { a: 3, b: 2 }
Использование immutability-helper
const data = { a: 1, b: 2 };
const key = 'a';
const newData = update(data, { [key]: { $set: 3 } });
// { a: 3, b: 2 }

Глубокая вложенность

В примерах выше в основном можно обходиться стандартными средствами JS, и только в некоторых ситуациях удобнее пользоваться сторонними решениями. В реальном коде всё будет также, особенно если учитывать рекомендацию React и держать состояние максимально плоским. Но в некоторых ситуациях данные, которые нужно изменить, находятся не на поверхности, а в глубине структур. К сожалению, в этих ситуациях обычный JS-код будет раздуваться. И тут уже точно не обойтись без дополнительных библиотек.

import update from 'immutability-helper';

const myData = {
  x: { y: { z: 5 } },
  a: { b: [1, 2] },
};

const newData = update(myData, {
  x: { y: { z: { $set: 7 } } },
  a: { b: { $push: [9] } }
});
console.log(newData)
// => { x: { y: { z: 7 } }, a: { b: [ 1, 2, 9 ] } }

https://repl.it/@hexlet/js-react-immutability-helper

Аналоги

immutability-helper — не единственная библиотека для подобных задач. Вот ещё несколько популярных:

  • immutable-js - основана на персистентных данных;
  • updeep - активно использует каррирование.

<span class="translation_missing" title="translation missing: ru.web.courses.lessons.mentors.mentor_avatars">Mentor Avatars</span>

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят менторы из команды Хекслета или другие студенты.

Для полного доступа к курсу нужна профессиональная подписка

Профессиональная подписка откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, даст возможность обращаться за помощью к менторам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
115
курсов
892
упражнения
2241
час теории
3196
тестов

Зарегистрироваться

или войти в аккаунт

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 115 курсов, 2000+ часов теории
  • 800 практических заданий в браузере
  • 250 000 студентов

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Rambler
Логотип компании Bookmate
Логотип компании Botmother

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».