Эта статья была впервые опубликована на Pragmatic Coder членом основной команды Aurelia Вильданом Софтиком. Если вам нравится это, почему бы не пойти туда и проверить некоторые другие его работы. И, если вы заинтересованы в том, чтобы быть в курсе последних новостей, связанных с Аурелией, вы можете подписаться на их официальную рассылку здесь .
Мы не можем игнорировать постоянно растущую важность смены парадигм, независимо от того, говорим ли мы о социальных, политических или программных вопросах. В последнее время интерфейсная веб-разработка проявляет все больший интерес к контейнерам с предсказуемым состоянием , представленным такими концепциями, как Flux, и популярными в Redux . Одновременно, тенденция к более функциональному стилю программирования — особенно к компонентному составу — изменила наш подход к созданию приложений.
На первый взгляд, ни одна из этих идей не может показаться настолько важной или изменяющей мир сама по себе, но вместе они могут обеспечить отличный опыт для разработчиков. Я не собираюсь судить, является ли это лучшим подходом по сравнению с известными понятиями, такими как MVVM и классические сервисы. Скорее, я хотел бы поделиться подходом, который поможет вам объединить обе концепции, чтобы получить лучшее из обоих миров.
В этой статье рассказывается о теории, реальном коде и полном примере, который можно найти на GitHub . Источники, включая шаблоны, полностью прокомментированы, чтобы объяснить выбор дизайна, а README репозитория содержит рекомендуемый способ просмотра примера . Таким образом, мы не будем тратить время на детали реализации, такие как использование RxJS, а перейдем непосредственно к пониманию основных концепций.
Современный подход к развитию
Современный подход к разработке использует единый магазин, который служит фундаментальной основой для вашего приложения. Идея состоит в том, что этот магазин содержит все данные, которые составляют ваше приложение. Содержимое вашего магазина — это состояние вашего приложения — моментальный снимок данных вашего приложения в определенный момент времени. С функциональной точки зрения, если бы мы представляли все наше приложение одной функцией renderApp
, состояние было бы аргументом, который мы передаем.
function renderApp(state): RenderedApplication
Если бы мы только хотели создавать статические сайты без какого-либо взаимодействия, мы бы уже были хороши и могли бы прекратить работу здесь. Тем не менее, большинство современных приложений обеспечивают множество взаимодействий. Поэтому, если состояние представляет собой моментальный снимок в определенный момент времени, событие можно рассматривать как триггер, который изменяет наше состояние с текущего на новое. Такое взаимодействие с пользователем можно сравнить с редуктором, который изменяет текущее состояние, применяя инструкции из определенного действия.
function userInteraction(oldState, ...actionInstructions): NewState
Модификация — опасная игра. Если мы изменим исходный источник, как мы узнаем разницу между новым и старым состоянием? Как таковая неизменность является ключевым аспектом современных подходов, поскольку она поддерживает исходный источник и создает измененную копию вашего нового состояния. Таким образом, текущее состояние становится старым, а взаимодействие создает следующее текущее состояние.
CURRENT STATE --> USER INTERACTION --> NEW STATE renderApp(currentState) --> userInteraction(currentState, ...) --> renderApp(newState)
Прошлое, настоящее и будущее являются снимками состояния после определенного количества действий. Помня об этом, мы можем переместить текущее состояние назад, изменив действия и вернувшись в предыдущее состояние.
NEW (aka CURRENT STATE) --> USER INTERACTION * -1 --> CURRENT (aka OLD STATE) renderApp(newState) --> userInteraction(newState, ...) --> renderApp(currentState)
Интересным моментом здесь является то, что последовательность функциональных вызовов не меняется — меняются только их входы. Таким образом, мы можем заключить, что на состояние влияют исключительно действия и что при заданном входном сигнале мы всегда можем ожидать одного и того же результата. Это отражает природу чистых компонентов.
Единый контролируемый магазин
Единственное контролируемое хранилище начинает иметь смысл, так как, если мы можем ограничить все изменения в одном месте, мы сохраняем контроль над результатом, тем самым отображая наше приложение. Это наш магазин. Такие решения, как Redux, заставляют вас жестко проектировать и создавать ваше приложение, которое в конечном итоге может не соответствовать вашим целям.
Еще одна важная вещь, которую следует иметь в виду, заключается в том, что, хотя люди не хотят менять поведение и приспосабливаться к новым парадигмам, это в два раза больше для корпоративного предприятия. Следовательно, применение принципиально иного подхода к разработке существующего программного обеспечения является сложной задачей.
Разработчики, работающие с Aurelia, часто имеют четкое представление о шаблоне MVVM, который большую часть времени продвигает услуги в качестве лучшей практики, позволяющей отделить бизнес-логику от логики пользовательского интерфейса. В сочетании с внедрением зависимостей Aurelia мы получаем действия по обработке одноэлементных экземпляров. Тем не менее, ограничение магазина отсутствует, так как сервис сам по себе не определяет, где и как вы должны получить доступ и изменить ваши данные. Служба поддерживает состояние? Вы разрешаете изменять его только с помощью сеттеров и получать к нему доступ через геттеры? Эта гибкость является как благословением, так и проклятием, поскольку означает, что вы можете создавать и структурировать свои приложения так, как вам хочется — если у вас нет ни времени, ни интереса к этому думать ?
Использование методов обслуживания в качестве действий хранилища
Использование сервисных методов в качестве действий хранилища — это способ поддерживать доступ к данным через сервисы без необходимости изменять общую архитектуру приложения. Вместо того, чтобы вводить сервис, вы вводите магазин. Вместо доступа к методам обслуживания вы подписываетесь на изменения единого состояния и запускаете действия в хранилище. Затем они сами вызывают методы обслуживания, обновляют состояние и, таким образом, запускают перерисовку.
Как компоненты взаимодействуют с магазином
Визуализация приложений с компонентами
Это делается в Аурелии с помощью пользовательских элементов. Как и в случае с React и другими ориентированными на функциональное реактивное программирование (FRP) средами, это облегчает составление компонентов. Работа с одним состоянием внезапно заставит вас принять понятие тупой против умных компонентов и компонентов высшего порядка (HOC). Почему? Хорошо, начнем с HOC. Его единственная цель состоит в том, чтобы ссылаться и синхронизировать одно состояние и распространять либо себя, либо свои действия и частичные данные на его дочерние компоненты через входы.
В Aurelia это означает, что вы будете использовать пользовательский элемент, который внедряет хранилище и создает подписку на его изменения (пример HOC VM) . Ссылка на состояние затем передается интеллектуальным элементам, а частичные данные — немым элементам с помощью возможных действий (пример HOC View) .
Разница между умным и немым компонентом / элементом определяется тем, знает ли он о магазине или полностью изолирован от остального приложения и получает все свои данные, передаваемые ему через входы / атрибуты.
Тупые компоненты отделены от окружающей среды и, таким образом, могут быть более легко использованы повторно. Как правило, если вы хотите создать простые презентационные компоненты, которые отображают только те данные, которые им предоставлены, и передают обратные вызовы заданным действиям, то вы должны использовать тупые компоненты. Если компонент, с другой стороны, не будет повторно использоваться в других местах и имеет более сложное состояние пользовательского интерфейса для обработки, вы, вероятно, захотите использовать интеллектуальные компоненты. Держите их счет как можно меньше, хотя.
Мы рассмотрели довольно много здесь. Теперь я рекомендую взглянуть на пример кода на GitHub . Если у вас есть вопросы или комментарии, я хотел бы услышать их в обсуждении ниже.
Фото предоставлено: ihuikhh: Сборка велосипеда через Pixabay (лицензия)