Эта страница переведена PageTurner AI (бета). Не одобрена официально проектом. Нашли ошибку? Сообщить о проблеме →
(Краткая) история Redux
2011: Фреймворки JS MVC
Ранние JavaScript MVC фреймворки, такие как AngularJS, Ember и Backbone, имели проблемы. AngularJS пытался обеспечить разделение "контроллеров" и шаблонов, но ничто не мешало написать <div onClick="$ctrl.some.deeply.nested.field = 123"> прямо в шаблоне. В свою очередь, Backbone основывался на генераторах событий — модели, коллекции и представления могли генерировать события. Например, модели могли создавать событие "change:firstName", на которое подписывались представления. Однако любой код мог подписаться на эти события и запускать дополнительную логику, что могло порождать ещё больше событий.
Это делало такие фреймворки крайне сложными для отладки и поддержки. Обновление одного поля в модели могло запускать десятки событий и логики по всему приложению, а любой шаблон мог изменять состояние в произвольный момент, что делало невозможным предсказать последствия обновления состояния.
2014: Flux
В 2012-2013 годах, когда React впервые публично выпустили, Facebook уже использовал его внутренне несколько лет. Они столкнулись с проблемой: множество независимых компонентов интерфейса требовали доступ к одним данным (например, "количество непрочитанных уведомлений"), но организовать эту логику с кодом в стиле Backbone оказалось сложно.
В итоге Facebook разработал паттерн "Flux": создание нескольких синглтонных хранилищ (Stores), таких как PostsStore и CommentsStore. Каждый экземпляр хранилища регистрировался в Dispatcher, и единственным способом обновить хранилище был вызов Dispatcher.dispatch({type: "somethingHappened"}). Этот простой объект назвали "действием" (action). Идея заключалась в полуцентрализованной логике обновления состояния — произвольные части приложения не могли напрямую изменять состояние, делая все обновления предсказуемыми.
Facebook представил концепцию "Flux Architecture" около 2014 года, но не предоставил готовую библиотеку. Это побудило сообщество React создать десятки Flux-инспирированных библиотек с вариациями паттерна.
2015: Рождение Redux
В середине 2015 года Дэн Абрамов начал разрабатывать ещё одну Flux-инспирированную библиотеку — Redux. Целью была демонстрация "отладки путешествием во времени" (time-travel debugging) для доклада на конференции. Библиотека использовала Flux-паттерн, но с применением принципов функционального программирования. Вместо экземпляров хранилищ использовались предсказуемые функции-редьюсеры с неизменяемыми обновлениями. Это позволяло "перемещаться во времени" для просмотра состояния в разные моменты, делая код более прозрачным, тестируемым и понятным.
Redux вышел в 2015 году и быстро вытеснил другие Flux-библиотеки. Его рано приняли продвинутые разработчики экосистемы React, и к 2016 многие утверждали: "Если используешь React, обязан использовать Redux". (Откровенно говоря, это привело к избыточному применению Redux там, где он не был нужен!)
Также стоит отметить, что тогда в React был только устаревший Context API, который фактически не работал: он не мог корректно передавать обновлённые значения вниз. Можно было поместить генераторы событий в Context и подписываться на них, но для передачи простых данных он не подходил. Поэтому многие начали использовать Redux как способ стабильно распространять обновлённые значения по всему приложению.
Дэн с самого начала говорил: «Redux создан не для того, чтобы писать меньше кода — он нужен для предсказуемости и понятности». Частично это достигается за счёт единообразного подхода: обновление состояния происходит через редюсеры, поэтому вы всегда можете посмотреть их логику и понять, какие значения может принимать состояние, какие действия возможны и какие изменения они вызывают. Кроме того, логика выносится за пределы дерева компонентов, так что интерфейс в основном лишь сообщает о произошедшем событии, а сами компоненты становятся проще. Код, написанный в виде чистых функций (как редюсеры и селекторы), проще для понимания: аргументы на входе, результат на выходе, и больше ничего. Наконец, дизайн Redux позволил создать Redux DevTools, которые показывают удобный список всех диспетчеризованных действий, их содержимое и состояние, а также изменения, произошедшие после каждого действия.
Первые шаблоны Redux были особенно многословными. Обычно создавали actions/todos.js, reducers/todos.js и constants/todos.js только для того, чтобы определить один тип действия (const ADD_TODO = "ADD_TODO"), функцию-создатель действия и обработчик в редюсере. Кроме того, приходилось вручную писать иммутабельные обновления с помощью операторов расширения (spread), в которых легко было допустить ошибку. Разработчики действительно кэшировали данные сервера в Redux, но для этого требовалось много ручного кода: написание санков для получения данных, диспетчеризация действий с полученными данными и управление статусом кэша в редюсерах.
Redux стал популярен несмотря на этот шаблонный код, но именно он всегда вызывал больше всего нареканий.
2017: Конкуренция в экосистеме
К 2017-2018 годам ситуация изменилась. Сообщество стало больше фокусироваться на «получении и кэшировании данных», а не на «управлении состоянием на клиенте», и тогда появились такие библиотеки, как Apollo, React Query, SWR и Urql для работы с данными. В то же время вышла новая версия React Context API, которая действительно корректно передаёт обновлённые значения по дереву компонентов.
Это означало, что Redux больше не был так необходим, как раньше: теперь существовали другие инструменты, решавшие многие из тех же проблем, с разной степенью перекрытия функциональности (и часто с меньшим количеством кода). Постоянные жалобы на «шаблонный код» также вызывали беспокойство у пользователей Redux.
2019: Redux Toolkit
Поэтому в 2019 году мы разработали и выпустили Redux Toolkit (RTK) — более простой способ писать ту же логику Redux с меньшим количеством кода. RTK — это всё ещё «Redux» (единое хранилище, диспетчеризация действий для обновления состояния через редюсеры с иммутабельными обновлениями), но с более простым API и лучшими стандартными поведением. В его состав также вошёл RTK Query — наша встроенная библиотека для получения и кэширования данных, вдохновлённая React Query и Apollo.
Сегодня RTK — это стандартный способ написания логики Redux. Как и у всех инструментов, у него есть компромиссы. Использование RTK, вероятно, потребует немного больше кода, чем Zustand, но он также предоставляет полезные шаблоны для отделения логики приложения от интерфейса. Redux подходит не для каждого приложения, но он остаётся самой популярной библиотекой управления состоянием для React-приложений, имеет отличную документацию и предоставляет множество функций, помогающих создавать приложения с единообразной и предсказуемой структурой.
Дополнительные материалы
-
Почему React Context — не инструмент для «управления состоянием» (и почему он не заменяет Redux)
-
Археология Redux и заметки о дизайне (со ссылками на ранние обсуждения дизайна и описаниями целей проекта)