Вы разрабатываете веб-компоненты в виде губок или посудомоечных машин? Или оба? Осторожно, спойлеры! Я думаю, вам следует сделать и то, и другое. Этот пост предназначен для обсуждения моих нескончаемых сомнений относительно объема компонентов, ответственности и границ, другими словами, это еще один пост о презентационных компонентах и контейнерах (или как вы их называете) .

Я начну с некоторых цитат, которые нашел во время поиска в славном Интернете:

«Сделайте компонент, а не швейцарский нож. Визуальные компоненты должны соответствовать некоторым правилам. Компонент не должен напрямую связываться с магазином или вызывать API. Если мы добавим это к нашему компоненту, его невозможно будет восстановить. И весь смысл компонентов в том, чтобы их повторно использовать ».

Эдер Негрете на медиуме

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

Дэн Абрамов - соавтор Redux

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

Этот выбор существенно влияет на то, как вы проектируете компоненты, централизация приведет только к _представительным компонентам_, а децентрализация приведет к интеллектуальным компонентам или контейнерам. Возвращаясь к аналогии губки с посудомоечной машиной, презентационные компоненты - это губки, вы можете использовать их для чего угодно: мыть машину, мыть посуду, мыть пол и т. Д. Между тем, посудомоечные машины могут мыть только посуду. , но мыть посуду в посудомоечной машине гораздо удобнее, чем губкой. Посудомоечная машина умеет мыть посуду и управляет всеми необходимыми средствами для этого (мыло, вода, сияющая жидкость). Опять же, губки можно использовать многократно, а посудомоечные машины - удобно.

Возвращаясь к централизации и децентрализации, мы можем сказать, что обе крайности практически неприменимы.

Централизация всего состояния приложения и выборки данных в одной точке приведет к суперсложному корню, передаче большого количества бесполезной информации (вниз по дереву компонентов) и кучу обработки событий. Если сделать это неправильно, это может привести к проблемам с производительностью. Допустим, компонент X должен отображать информацию Z, но изначально X должен отображать только Z.title, ему не нужно Z.content. Таким образом, корень должен сначала получить частичную версию Z, а когда происходит какое-то событие (например, щелкнуть), он должен запросить остальную часть Z. Поскольку это позволяет корню узнать о мельчайших деталях о X, возникает соблазн получить всю Z не заниматься этим, и это ухудшает производительность. Так что, как правило, вы не будете централизовать все, на самом деле большинство фреймворков SPA предложат вам распределять логику на уровне маршрута / состояния.

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

Итак, обе крайности невозможны, но у вас все еще есть некоторая свобода решать, насколько адекватна децентрализация.

Основная причина централизации заключается в том, что чем больше компонент * знает * (о состоянии и другом коде), тем сложнее его повторно использовать. Другой веский аргумент - это контроль состояния приложения и обмена данными. Если каждый компонент может управлять состоянием приложения, будет сложно поддерживать приложение, так как трудно понять, кто что и когда делает с состоянием приложения. То же самое можно сказать и о бэкэнд-коммуникациях: если каждый компонент может делать HTTP-запросы, вы можете получить кучу избыточных запросов.

С другой стороны, концентрация всего состояния и всех HTTP-запросов в корне
(весь корень страницы) обычно нарушает принцип разделения проблем.
Это также может снизить ремонтопригодность, как писал Дэн Абрамов, когда вы Приняв эту стратегию, вы в конечном итоге передадите кучу свойств дочерним компонентам. Таким образом, если вы измените интерфейс какого-либо листового компонента, вы можете в конечном итоге изменить все корневые родители, которые используют этот компонент. Это также может увеличить количество копий-вставок в приложении, если у вас есть более сложные функции, которые должны быть в большем количестве мест. Например, если у вас есть функция чата, которую можно использовать более чем на одной странице, вам необходимо реплицировать все управление состоянием и вызовы API для всех родителей, которые используют этот компонент. Если вам придется изменить эту логику, у вас снова возникнет проблема с ремонтопригодностью.

Я еще не выяснил золотую середину для этого, но кажется, что если у вас достаточно сложный и достаточно независимый (от других информация на экране), который появляется во многих местах, я бы сделал его контейнером. Эти требования сильно ограничивают компоненты, которые являются кандидатами на роль контейнеров, и большинство приложений могут жить без них (вот почему я думаю, что многие люди выступают за централизованный подход). Вот несколько примеров приложений, которые я бы хотел спроектировать как контейнеры: пользовательский интерфейс чата (например, чат Facebook или Intercom), панель поиска, возможно, создатель твита. Все они могут быть сложными и очень оторванными от экрана, который видит пользователь.

Замечания: это мой первый пост на среднем уровне, но не первый, я тестирую его на нем. Вы можете прочитать другие материалы на https://blog.sennav.com