Сегодня друг попросил меня выложить, что я знаю о создании приложений с помощью React и Redux. Поскольку я все равно трачу время на то, чтобы записать эти идеи, я решил опубликовать их здесь, чтобы они принесли наибольшую пользу наибольшему количеству людей. Архитектура приложений React/Redux сложна, и, поскольку существует так много гибкости в том, как вы можете соединять элементы, легко потеряться в мешанине из множества вариантов и компромиссов. Надеюсь, я смогу немного расчистить путь, чтобы вы не чувствовали себя таким потерянным в сорняках.

Почему реагировать? Почему Редукс?

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

Я хочу мотивировать это обсуждение, рассказав о своем опыте написания одностраничных веб-приложений. Я проектировал и создавал приложения на jQuery, Backbone, Angular 1 и React. Хотя я обнаружил, что и jQuery, и Backbone отлично подходят для начальной разработки приложений, я заметил, что по мере того, как приложения лишь немного увеличивались в размере и сложности, их стало трудно поддерживать; абстракции, предоставляемые этими фреймворками, сами по себе были недостаточно мощными для больших приложений.

Все изменилось, когда я начал работать в ныне несуществующем стартапе Marketwiise. Я согласился на эту работу, потому что это была возможность спроектировать и создать полнофункциональное приложение с использованием Node, Express и Angular. Я все еще был новичком в этих технологиях, когда начинал, но я быстро освоил их и обнаружил, что они мне действительно нравятся, особенно Angular с его встроенными промисами, внедрением зависимостей, системой модулей и двусторонней привязкой данных. В то время это казалось огромным скачком вперед.

Но по мере того, как веб-приложение становилось все сложнее, как и в случае с более примитивными фреймворками, его стало трудно поддерживать. Та самая двусторонняя привязка данных, которая вначале упрощала написание приложения, вскоре оказалась проблематичной. Длинные цепочки привязки данных по всему приложению означали, что я действительно не понимал, как я моделирую или перемещаю свои данные. И если вы не понимаете, как структурированы ваши данные, вам будет сложно понять и предсказать, что делает ваше приложение.

И если этой проблемы с вырожденной моделью данных было недостаточно, то чертова система компонентов была слишком сложной. Так называемые директивы могут быть пользовательскими тегами элементов HTML, атрибутами элементов, именами классов и даже комментариями! Этот запутанный набор вариантов усугублялся тем фактом, что сама директива API была невероятно сложной.

React и Redux спешат на помощь

React и Redux решают эти проблемы. Во-первых, React предоставляет гораздо более простой компонент и систему шаблонов. Поскольку его легче понять, как только вы освоите его, проще писать сложные, удобные в сопровождении приложения.

Однако, поскольку компоненты React могут хранить состояние, вы можете столкнуться с той же проблемой, что и у меня в Angular. Когда у вас есть достаточно компонентов, хранящих состояние и передающих его другим компонентам с помощью различных средств связи, вы можете получить очень непредсказуемую цепочку данных.

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

Это настолько важно, что я действительно хочу вбить это в ваши головы: 1) смысл React в том, чтобы упростить сборку компонентов и шаблонов; 2) суть Redux заключается в облегчении единого предсказуемого потока данных из приложения в единую унифицированную модель данных и обратно в цикле в приложение. Это про простоту и предсказуемость.

Элементы успешного приложения React/Redux

Я могу написать более подробно об этих темах позже, но сейчас я просто хочу набросать основу успешного приложения React/Redux.

Инструменты сборки

Мне нравится писать передовой Javascript, поэтому я всегда использую Babel. Мне нравятся генераторы, обещания и многие другие функции, которые начинают стандартизироваться.

И хотя я лично чувствую, что могу многое сделать, используя только Webpack и npm, в прошлом я использовал Browserify, Cake, Grunt и Gulp. Также на глаза попались Rollup и System.js, но я с ними пока не игрался.

Магазин Редукс

Redux следует использовать для хранения глобального состояния, и лучше всего максимально нормализовать хранилище Redux, потому что это модель данных для вашего приложения, и чтобы понять поведение вашего приложения, вам нужно, чтобы эти данные были чисто и организованно.

И когда дело доходит до вашего магазина, есть один важный компромисс, на который я хочу обратить ваше внимание: простые объекты Javascript против неизменяемых структур данных.

Основное преимущество объектов Javascript здесь заключается в том, что у вас уже будет интуитивное представление о том, как работать в вашем магазине. Вы можете использовать те же операции Javascript, которые вы использовали во всех приложениях, которые вы создавали в прошлом. Но за это удобство приходится платить. Поскольку объекты Javascript полагаются на ссылки, существует опасность того, что ваше приложение будет делиться ссылками на объекты с хранилищем, что позволяет компонентам React легко изменять состояние приложения без отправки действий Redux. Это можно смягчить, используя такие вещи, как Object.assign() для создания поверхностных копий объектов хранилища Redux, но вы никогда не устраните проблему полностью, если не сделаете глубокие копии, а это может быть очень дорого.

Теперь, если вы готовы выйти за пределы своей зоны комфорта, я бы порекомендовал использовать библиотеку неизменяемых структур данных для реализации вашего магазина. Это потребует предварительного обучения, и вы почувствуете, что это замедляет ваш процесс разработки, но есть огромные выгоды. Неизменяемые структуры данных трудно изменить за пределами вашего хранилища, а диспетчеризация действий становится менее затратной, поскольку вы можете обновлять данные, не копируя всю структуру данных. Мне нравится использовать для этой цели Immutable.js.

реагировать-восстановить и повторно выбрать

Следующий большой столп архитектуры React/Redux связан с тем, как вы передаете данные из своего хранилища в свои компоненты React. Мои первые попытки заключались в том, чтобы сбросить весь мой магазин в реквизит моего корневого компонента, а затем использовать этот корневой компонент для установки свойств компонентов на всем протяжении дерева компонентов. Это плохо по ряду причин. Первая большая проблема заключается в том, что ваши компоненты легко зависят от структуры вашего хранилища Redux, и такая тесная связь быстро становится проблемой сопровождения. И, в дополнение к тесной связи, ваши компоненты будут брать на себя много кода для вычисления значений из состояния, затемняя логику представления слишком большим количеством нестандартного кода преобразования данных.

Вы можете избежать этого, используя reselect. reselect позволяет вам создавать запоминающие селекторные функции, которые вычисляют производные данные из вашего хранилища. Это помогает вам ограничить объем преобразования данных в ваших компонентах, отделяет вашу модель данных от архитектуры вашего компонента и повышает эффективность, поскольку производные данные пересчитываются только в том случае, если данные в вашем хранилище изменяются.

В дополнение к повторному выбору я рекомендую использовать react-redux для внедрения состояния приложения в ваши компоненты. В react-redux есть компонент под названием Provider, который внедряет хранилище в ваше приложение через корневой компонент с помощью React context API. Затем вы можете использовать функцию connect() для внедрения свойств в ваши компоненты. С помощью connect() вы можете использовать селекторы для вычисления и вставки состояния с помощью параметра mapStateToProps, а также вы можете внедрить автодиспетчерские функции создания действий с помощью mapDispatchToProps. Это позволяет вам отделить ваши компоненты React от Redux, потому что ваши компоненты будут в блаженном неведении относительно store.getState() и store.dispatch(). Но что еще лучше в этом расположении, так это то, что подключенные компоненты по своей конструкции будут получать меньше свойств (в идеале нулевых реквизитов) от своих родителей, что упрощает изменение и обслуживание вашего компонента render() методы.

Маршрутизация на стороне клиента

Здесь мне нечего сказать. Я использовал реактивный маршрутизатор в прошлом. Мне кажется, это нормально.

Асинхронные операции (HTTP, AJAX и т. д.)

Еще одна огромная проблема в приложениях React/Redux — решить, где разместить логику для отправки и получения данных. Ваши вызовы AJAX и код веб-сокета должны куда-то идти. Когда я впервые начал создавать приложения React/Redux, я на самом деле поместил много этого кода в свои редьюсеры. Однако это был ужасный выбор: редукторы должны просто обновить хранилище Redux.

Я обнаружил, что лучший способ справиться с этим — воспользоваться промежуточным программным обеспечением Redux. На мой взгляд, ваши лучшие варианты — redux-thunk, redux-promise-middleware и redux-saga. Я использовал как redux-thunk, так и redux-promise-middleware, и из этих двух я предпочитаю промежуточное ПО promise. По моему опыту, несмотря на то, что с преобразователями легко начать и работать, они становятся беспорядочными, когда вы начинаете хотеть упорядочивать множество асинхронных операций. И, поскольку я начал использовать промежуточное программное обеспечение обещания на моем текущем концерте, я нахожу написание сложных приложений React/Redux гораздо более приятным занятием.

В заключение я хочу прояснить, что, хотя мне еще предстоит использовать redux-saga в приложении, я думаю, что это выглядит потрясающе, но мне кажется, что оно одновременно очень тонкое и немного сложное. , поэтому я бы рекомендовал использовать его только в том случае, если он вам действительно нужен.

Для получения дополнительной информации по этой теме прочитайте эту статью от Надера Дабита.

Вывод

Для успешной разработки и поддержки приложений React/Redux нужно многое, и я хочу прояснить, что то, что я здесь написал, далеко не исчерпывающее, поэтому убедитесь, что вы делаете свою домашнюю работу и пробуете. При этом то, что я сделал здесь, — это дать некоторое представление о наиболее важных дизайнерских решениях, которые необходимо учитывать при создании приложений с помощью React и Redux. Надеюсь, это сэкономит вам время и страдания.

Привет, Пол Рене Николс.