Долго думал, с чего начать свой путь в статьи на технические темы и решил начать с того, с чем мне приходится работать каждый день и в создании чего, по моему мнению, часто совершают ошибки, как менее опытные разработчики (мало опыта, не понимают, зачем нужны компоненты), так и более опытные (разные “универсальные компоненты” на все случаи, которые в итоге невозможно переиспользовать, слишком “жирные”, либо вроде всё окей, но оказываются совершенно не расширяемыми). Обо всём этом и пойдет речь в статье.
Компоненты - составные части нашего приложения. Мне часто представляются они как детали конструктора Lego. Сотни разных вариантов на любой вкус и цвет, а общие принципы позволяли комбинировать их множеством способов, строя шикарные замки, космические корабли и многое другое.
Все кто сталкивался с ним, знают, что маленькую деталь “однушку” можно воткнуть почти хоть куда, но для быстрого заполнения большого участка, нужна длинная плашка. Как детали от конструктора при строительстве очередного шедевра, разные компоненты в проекте должны быть:
- Значимыми (хорошо выполняющими возложенную на них задачу)
- Переиспользуемыми (если такая деталь нужна ещё где-то, то её можно без проблем воткнуть)
- Очевидными (да, иногда были детальки с дырочкой посередине, сложные механизмы или мозговыносящие Bionicle, но с ними шла отличная инструкция)
- Надежными (не очень-то охота строить систему из китайского конструктора, хотя он бывает и не плох :-))
Наружу из деталей Lego торчит интерфейс в виде выпирающих точек и разных отверстий, благодаря которому есть возможность соединять детали вместе (ассоциация) - с помощью присобачевания в боковую дырочку (через пропсы, render props, агрегация) или соединять друг под дружкой (children/slots - композиция).
Как и все аналогии, эта хороша до определенного момента, и далее мы будем говорить про состояние (state) компонентов, отделение логики от представления, про способы борьбы со сложностью компонентов.
Если исключить внутреннее состояние, компоненты в рамках фреймворков Vue и React можно представить в виде чистой функции, которая принимает некоторые свойства, а возвращает некоторый кусочек вашего интерфейса.
Добавляя состояние (любым доступным способом), набор операций для изменения этого состояния, а также не чистый мир браузера, мы получаем более сложные компоненты, не похожие на те, которые хотелось бы иметь в идеальном мире.
Состояние и набор операций превращает наши компоненты в конечный автомат (раньше, во времена jQuery состояние редко выделяли явно, а инструментов для управления состоянием особо не было, потому оно всегда уходило на второй план, и размывалось в логике обработчиков).
Да, с появлением состояния наши компоненты определённо усложнились, но те принципы, существующие во времена дизайна деталей Lego можно применить и здесь.
Мир React’а же полнится разными подходами к созданию компонентов. Исходя из задачи, у разработчиков появляется выбор, что же использовать, и как хороший инструмент React не ограничивает в выборе подхода. Со многими базовыми паттернами начинающий разработчик знакомится еще в официальной документации, также есть отличный набор полезных подходов для создания более гибких компонентов, которые подробно рассматриваются на воркшопах и курсах от Kent Dodds.
Если честно, начал эту статью писать в заметках год назад, потому она получилась довольно обрывочной, а с того времяни я довольно сильно подрос в понимании происходящего в вэбе. Компоненты для view
слоя проникли в другие языки и платформы (для Android есть множество библиотек, фрагменты, в Swift добавили SwiftUI). Очевидно, что наследие виджетов из QT и Visual Basic (возможно, они где-то еще были до этого, но мне не знакомы) переросло в довольно популярный, мощный подход, являющийся сейчас мейнстримом.
В итоге я решил не вымучивать из себя продолжать писать об этом, хотя мыслей на тему много и за время фронтенд-разработки я повидал множество как хороших, так и плохих решений проблем интерфейсов с помощью компонентов. Дам лишь простой вывод из всех мыслей: важны всё теже SOLID принципы, фреймвоки - деталь, а неявное привносит много проблем.