Главная | Все статьи | Код

Как Immer покоряет React

Время чтения статьи ~8 минут 29
Как Immer покоряет React главное изображение

Неизменяемость меняется. Ладно, как минимум меняется реализация неизменяемости в React. Шутки в сторону, дальше речь идёт о серьёзных вещах.

История

Необходимость в неизменяемости в JavaScript неочевидна. Классически, главным преимуществом неизменяемости считается многопоточность. Но поскольку JavaScript — однопоточный язык, этот вариант не подходит.

Историю неизменяемости в React можно проследить с декабря 2013 года. Тогда Дэвид Нолен представил Om — UI-фреймворк на ClojureScript, который работает поверх React. Oн оказался быстрее самого React.

Как обёртка может быть быстрее исходной технологии? Дэвид Нолен объяснил это в выступлении. Краткая суть: скорость Om объясняется неизменяемостью данных. React тратит много ресурсов на согласования. Оказалось, что эту работу можно не выполнять, если удаётся использовать поверхностное сравнение объектов и массивов, а также мемоизацию. С помощью механизма согласования Fiber React активно использует мемоизацию, чтобы не выполнять действия повторно.

Ли Байрон (Lee Byron) сделал идею неизменяемости в React мейнстримом в 2015 году с помощью Immutable.js. Запись выступления есть на Vimeo. Immutable.js — специальная библиотека для реализации неизменяемости в JavaScript.

Сообщество Redux легко приняло Immutable.js, так как философия этого инструмента похожа на философию Flux. Так решилась проблема неизменяемости. Верно?

Люди, культура и сообщество Immer

В начале 2018 года Майкл Вестстрейт (Michael Weststrate) запустил проект с открытым исходным кодом Immer. Перед тем, как читать дальше, рекомендуется ознакомиться с сообщением о запуске Immer, а также с readme проекта. Также полезно посмотреть выступление Вестстрейта на конференции React Finland (вот презентация).

Вот несколько восторженных реакций на появление Immer. Первая от корпоративного мира, компания Workday Engineering:

— Несмотря на недостатки, Immer — отличный инструмент. К тому же он лёгкий, простой и мощный. Разработчикам Immer нравится. Этот инструмент легко изучать, и он не требует серьезных изменений в проектах.

Вторая от преподавателя Кори Хаус:

— Предпочитаю использовать Immer.

Третья от мейнтейнеров опенсорс-проектов Марка Эриксона:

— Использую Immer.

И Брэндона Дейла:

— В react-copy-write используется Immer. Он позволяет изменять черновик объекта, чтобы выполнять неизменяемые обновления. Поскольку здесь реализовано совместное использование, react-copy-write выполняет повторный рендеринг только когда это необходимо.

Ещё один отзыв от Себастиана Маркбэйджа из команды React:

— Если вам нравится MobX, рекомендую следить за проектом Майкла Вестстрейта Immer. MobX ушёл в сторону от пути, по которому идёт React. А Immer точно следует этому пути.

Об актуальности Immer в контексте React

Вокруг Immer происходит какая-то магия, ни больше ни меньше. Поэтому стоит детально разобраться с философией Immer и попробовать понять, где она совпадает с принципами React.

Когда разговор идёт о понимании философии React, которая в той или иной степени отличается от актуального состояния библиотеки React, автор оригинальной публикации рекомендует ознакомиться с двумя документами. Это раздел «Принципы проектирования React» в официальной документации, а также react-basics — формальное объяснение ментальной модели React. В этих документах есть три концепции, релевантные Immer.

Временная изменяемость

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

// MobX?
clickHandler = () => this.state.count++

Хотя мы можем изменить React, чтобы он поддерживал такой код. Но вместо этого мы пишем так:

// React
clickHandler = () => this.setState(state => ({
    count: state.count + 1
}))

Это очень похоже на Producers в Immer:

// Immer
const nextState = produce(currentState, draft => {
    draft.count = draft.count + 1
})

Совместимость

Одна из самых больших проблем Immutable.js — сложность реализации совместимости. Мы используем Immutable.js в Netlify более двух лет. И мы постоянно вспоминаем, что используем «не просто JavaScript», когда пытаемся, например, деструктурировать Map’ы Immutable.js:

const map1 = Immutable.Map({ foo: 1, bar: 2 })
const { foo, bar } = map1
console.log(foo) // undefined
console.log(bar) // undefined

Это приводит к утечке абстракции, так как приходится всё время думать, обёрнуты ли переменные, с которыми мы работаем, с помощью Immutable.js.

В Immer все объекты и массивы — это обычные объекты и массивы JavaScript, поэтому с ними можно работать так, как вы привыкли делать это в JavaScript.

// Immer
const map1 = { foo: 1, bar: 2 }
const map2 = produce(map1, draft => {
    draft.foo += 10
})
const { foo, bar } = map2
console.log(foo) // 11
console.log(map1.bar === bar) // true

Это та же философия, которая привела к успеху React. Благодаря фокусировке на совместимости возможно частичное внедрение вместо необходимости преобразовывать всё и сразу. Также совместимость позволяет использовать React с другими библиотеками в экосистеме JavaScript, которые ожидают, что приходящие к ним данные — это чистый JavaScript. Такую же цель преследовал Брендан Айх, когда предложил прокси в 2010 году. Immer — отличный инструмент расширения языка, для использования которого не надо ничего ломать и даже резко менять.

Отладка

Для отладки и трассировки в Immer применяются Patches. Потенциально на основе Patches можно даже создать инструменты разработчика.

Это похоже на то, как реализована отладка в React. Она включает отслеживание ошибочных обновлений UI. Также в React реализованы инструменты разработчика (ReactDevTools).

В Patches также есть возможность использовать undo/redo Redux. В источнике по ссылке смотрите примеры кода.

Выносливость

В экосистеме JavaScript используется термин churn или отток. Этим термином обозначают долю фреймворков и библиотек, которые были созданы, раскручены и затем заброшены создателями и сообществом. Способность определить «выносливые» инструменты, то есть инструменты, которые долго будут востребованными — залог стабильного роста и развития.

CEO Netlify Маттиас Биилман (Mathias Biilmann) рассказал о практиках, которые помогают определять «выносливые» инструменты:

  • изучайте историю;
  • люди, сообщество и культура играют важную роль;
  • всегда задавайте вопрос «зачем».

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

Стремительный взлёт Immer примечателен. Причиной этого успеха стало изучение исторического опыта, а также популярность в сообществе React. Последнее было бы невозможным без совпадения фундаментальной философии React с философией Immer.

Дэн Абрамов (Dan Abramov) отметил, что развитие технологии проходит через определённые циклы, и что люди меняют парадигмы:

— Рецепт успеха: возьмите что-то, что легко отлаживать, и сделайте так, чтобы работа с этим инструментом не раздражала. Спасибо Майклу Вестстрейту за Immer.

Это важный инсайт — успех Immer стал возможен, так как сообщество React уже оценило преимущества неизменяемости. Immer фокусируется на тех же преимуществах, что и React, при этом он улучшает API теми же способами, которые сделали успешным React.

Лучший способ начать работать с Immer — использовать редьюсеры Redux или шаблоны React setState. Затем обращайте внимание на другие библиотеки на базе Immer, например, Redux Starter Kit, а также не связанные с Redux инструменты управления состоянием, например, react-copy-write, immer-wieder, bey.

Адаптированный перевод статьи The Rise of Immer in React by Swyx. Мнение администрации «Хекслета» может не совпадать с мнением автора оригинальной публикации.

Аватар пользователя Дмитрий Дементий
Дмитрий Дементий 30 октября 2019
29
Похожие статьи
Рекомендуемые программы
профессия
от 25 000 ₸ в месяц
Разработка фронтенд-компонентов для веб-приложений
10 месяцев
с нуля
Старт 26 декабря
профессия
от 25 000 ₸ в месяц
Разработка веб-приложений на Django
10 месяцев
с нуля
Старт 26 декабря
профессия
от 14 960 ₸ в месяц
Ручное тестирование веб-приложений
4 месяца
с нуля
Старт 26 декабря
профессия
от 25 000 ₸ в месяц
Разработка приложений на языке Java
10 месяцев
с нуля
Старт 26 декабря
профессия
от 24 542 ₸ в месяц
новый
Сбор, анализ и интерпретация данных
9 месяцев
с нуля
Старт 26 декабря
профессия
от 25 000 ₸ в месяц
Разработка веб-приложений на Laravel
10 месяцев
с нуля
Старт 26 декабря
профессия
от 28 908 ₸ в месяц
Создание веб-приложений со скоростью света
5 месяцев
c опытом
Старт 26 декабря
профессия
от 39 525 ₸ в месяц
Разработка фронтенд- и бэкенд-компонентов для веб-приложений
16 месяцев
с нуля
Старт 26 декабря
профессия
от 25 000 ₸ в месяц
Разработка бэкенд-компонентов для веб-приложений
10 месяцев
с нуля
Старт 26 декабря
профессия
новый
Автоматизированное тестирование веб-приложений на JavaScript
8 месяцев
c опытом
Старт 26 декабря