Как использование компонентов помогло выиграть «войну фреймворков»

Как использование компонентов помогло выиграть «войну фреймворков»

От автора: какие проблемы решает использование компонентов в разработке. Сравнение, преимущества и недостатки фреймворков React, Angular и Vue.

2018 знаменует конец усталости от JavaScript и конец «войны фреймворков»

Обычная карьера frontend/JavaScript разработчика включает в себя немного jQuery с соответствующими плагинами, после чего переход на React, Angular или Vue, и использование компонентов.

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

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

Компонентная и композиционная модель

Компонент – это элементарная единица во всех трех фреймворках. В React вы расширяете React.Component, в Angular мы настраиваем Module для хранения компонента/ов с помощью декораторов @NgModule и @Component. В Vue вы регистрируете компоненты в объекте Vue через Vue.component().

Все основано на компонентах, вкладывая один в другой, передавая данные между ними и т.д.

По композиционной модели компоненты должны быть автономными секциями или «частичками» вашего приложения, которые можно повторно использовать в более специфических контекстах. Их преимущество в том, что они позволяют инкапсулировать логику, предоставляя API гарантии: вы передаете в компонент x, y и z и получаете обратно поведение foo. Все что компонент делает внутри, вам не важно.

Состояние и мутация

Все эти фреймворки сталкиваются с проблемой привязки данных к DOM. Разработчику бы пришлось делать это вручную через jQuery, например.

Это значит, что самое базовое приложение (использующее фреймворк/библиотеку) будет хранить некое состояние. Модели Vue, Angular и React (т.е. не пользовательские библиотеки) немного отличаются.

Angular верит в то, что состояние должно мутироваться. Фреймворк позволяет передавать сервисы между компонентами и модулями, обычно поддерживая этот сервис как quasi-singleton через вставку зависимостей. Поэтому разработчик может легко написать контейнер data-sharing, который будет обновлять соответствующие компоненты, обычно через сервис, возвращий Observables и компоненты, хранящие подписку на них.

Vue использует систему реактивности для уведомления других частей приложения об изменении состояния. Это дает фреймворку преимущество в производительности, так как this.property на самом деле внутри использует сеттер, и Vue может отправлять обновления туда, где они нужны, а не просто куда угодно. Вычисляемые свойства – предпочтительный механизм составления состояния для рендера в шаблон.

React распространил представление о неизменности состояния в экосистеме JS. Состояние не обновляется мутацией (например через state.myProperty). Вместо этого для обновления вызывается метод компонента setState с данными.

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

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

Передача данных

Шаблоны передачи данных упрощаются с помощью компонентного приложения: общение происходит только от родителя к ребенку и наоборот.

В React для передачи данных передаются props и функции, которые позволяют обновлять состояние родителя из ребенка.

В Angular привязки Input и Output определяются в компоненте и ограничены в шаблоне. Поведение Output во многом похоже на события. Они вызываются детьми и ловятся родителями.

В Vue props передаются от родителя к ребенку, а ребенок может запускать события обратно к родителю.

Все три фреймворка одинаково решили проблему передачи состояния между соседними компонентами. Они находят ближайшего общего родителя в дереве и инкапсулируют состояние, после чего оно обновляется.

Жизненные циклы, обновления и повторный рендер

Компоненты в React, Vue и Angular обновляются, если меняется локальное состояние или props (inputs). Если вы не храните состояние локально, вы можете вынудить компоненты меняться только, когда меняются их props.

В React и Vue этим занимаются функциональные компоненты, а в Angular можно использовать стратегию определения изменений ChangeDetection.OnPush.

Жизненные циклы компонента есть во всех фреймворках под разными именами методов.

Все три обеспечивают монтаж/демонтаж, что означает, что компонент инициализируется в DOM, и что он больше не нужен соответственно.

Глобальные хранилища

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

Идея хранилища изначально популяризировала экосистема React с архитектурой Facebook flux. Flux передает действия в хранилище, которые знают, как обновить состояние хранилища в зависимости от типа действия.

В React это называется redux или MobX, у Vue официально поддерживается Vuex, а в Angular — ngrx/store.

Шаблон одного глобального хранилища поддерживается всеми этими фреймворками. Разница в том, что библиотеки относятся к экосистеме для Angular и React, а хранилище Vue поддерживает основная команда.

Дизайн решений этих хранилищ отражает идиоматические способы написания кода с помощью этих фреймворков: в Vue это объект и getter/setter, в Angular это Observables, хорошо организованные эффекты и т.д. У React самый лучший выбор: просто JS + чистые функции (Redux), реактивные наблюдатели за состоянием (MobX) или даже объекты чистого JS (unstated).

Типы и валидация данных

Валидация типов данных в приложении помогает в разработке и отладке.

JS не имеет статических типов, поэтому следить за типами, передавая данных через несколько компонентов и функций, становится сложно.

Vue и React решают это проблему валидацией типов prop. Компонент и его props определяются с помощью типизированных props. В режиме разработки библиотека смотрит, чтобы переданные props совпадали с типами набора prop. Эти аннотации и проверки убираются в продакшен сборках приложения/библиотеки. Поэтому все минусы этих проверок уходят там, где важнее всего производительность.

В Angular нет такого механизма валидации prop, который пользуется преимуществом TypeScript. Разработка со статическими входными и выходными данными – замечательный опыт. Но во время билда эти типы убираются. Определить несовпадение типов в момент runtime невозможно. Большая часть несовпадений в типах происходит в IDE или компиляторе.

React и Vue также можно вооружить системами типов, такими как TypeScript и Flow, что дает им аналогичные гарантии, как в Angular и TypeScript.

Шаблоны, стили и инструменты

Лучшие практики по файловой структуре приложения в Angular, Vue и React разные.

Angular придерживается одной папки на Module/Component, где будут лежать ваш TypeScript, шаблон и файлы стилей. Шаблоны и стили во встроенном компоненте Angular можно писать инлайн, но лучше делать это в отдельных файлах. Это хорошая идея для больших одностраничных приложений.

Vue называется «прогрессивным фреймворком», потому что он предлагает различные функции в зависимости от размера разрабатываемого приложения. В простейшем случае (Vue в глобальном масштабе используется с использованием CDN и тега script), рекомендуется писать шаблоны инлайн. Vue также предлагает CLI и пакеты, которые интегрируются с инструментами построения, такими как webpack. Предпочтительным способом написания компонентов в этой среде является однофайловый компонент — файл с шаблоном, тег script и style. Vue-loader компилирует шаблон в JavaScript вместе с секцией скрипта и извлекает содержимое тега style в таблицу стилей во время сборки.

В React, поскольку логические и JSX-шаблоны не могут быть разделены, возникает вопрос только о стилях. Существует несколько ответов: обрабатывать стили раздельно, используйте webpack, чтобы извлекать import ‘my.css’ в таблицу стилей или использовать библиотеки CSS-in-JS.

Для небольших проектов Vue обладает более удобной эргономикой, для самого крупного корпоративного прецедента Angular имеет наибольшую структуру, React находится где-то посередине, где структура компонента остается как упражнение для разработчика, но рекомендуется использовать инструмент построения (по крайней мере, для компиляции JSX).

Тестирование и серверный рендер

Юнит тестирование в Angular в основном выполняется на классах компонентов TypeScript. Для проверки логики шаблона потребуется полная DOM-среда (например, безголовый браузер).

В React и Vue, благодаря использованию функций Virtual DOM и рендеринга, тестирование логики шаблона возможно с использованием enzyme и vue-test-utils соответственно.

Мелкий рендеринг компонентов означает, что отображается только первый «слой» дочерних элементов компонента, т.е. все компоненты, находящиеся в дочерних элементах, не полностью оцениваются (отображаются в HTML), вместо этого они остаются как ComponentName в дереве компонентов.

Эта возможность рендеринга без полной DOM-среды также полезна для серверного рендеринга приложения JavaScript. Vue имеет пакет vue-server-renderer и React ReactDOMServer.

Это позволяет приложению Node конвертировать гидратированное приложение Vue или React в разметку (HTML), обычно отправляемое обратно как ответ HTML для загрузки первой страницы.

Angular имеет аналогичную возможность компиляции и рендеринга, хотя эти функции меньше «встраиваются в существующее приложение» и больше «строят с учетом этих инструментов», поскольку некоторые функции фреймворка должны использоваться с осторожностью при использовании Angular Universal, что позволяет серверный рендеринг или AoT compiler, который компилирует шаблоны JavaScript и выполняет функции рендеринга.

Заключение

Сейчас можно активнее использовать компонентные фреймворки и плавне переключаться между ними.

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

Единственное, что все еще разделяет React, Vue и Angular, — это основные философии и примитивы, на которых они построены. React сильно зависит от разработчиков в выборе предпочтительных инструментов из экосистемы (или при необходимости их создания). Vue может начать с простого тега script, но также предоставляет набор инструментов для создания более крупных приложений (отдельные компоненты файлов, Vuex, vue-router, документацию и даже руководство по стилю). Angular направлен на большие приложения и сразу идет с обильным количеством структуры и кода (с использованием TypeScript), а также с глубоким охватом RxJS и Observables.

Автор: Hugo Di Francesco

Источник: https://codewithhugo.com/

Редакция: Команда webformyself.