Вы разрабатываете веб-компоненты в виде губок или посудомоечных машин? Или оба? Осторожно, спойлеры! Я думаю, вам следует сделать и то, и другое. Этот пост предназначен для обсуждения моих нескончаемых сомнений относительно объема компонентов, ответственности и границ, другими словами, это еще один пост о презентационных компонентах и контейнерах (или как вы их называете) .
Я начну с некоторых цитат, которые нашел во время поиска в славном Интернете:
«Сделайте компонент, а не швейцарский нож. Визуальные компоненты должны соответствовать некоторым правилам. Компонент не должен напрямую связываться с магазином или вызывать API. Если мы добавим это к нашему компоненту, его невозможно будет восстановить. И весь смысл компонентов в том, чтобы их повторно использовать ».
«Когда вы замечаете, что некоторые компоненты не используют реквизиты, которые они получают, а просто пересылают их вниз, и вам приходится перепрограммировать все эти промежуточные компоненты каждый раз, когда дочерним элементам требуется больше данных, самое время представить некоторые компоненты контейнера».
Эти две цитаты более или менее демонстрируют крайности спектра обязанностей веб-компонентов.
С одной стороны, теория заключается в централизации, поэтому все данные о состоянии и получении информации централизованы в корне приложения.
Вкл. с другой стороны, у нас есть все компоненты, которые хранят внутреннее состояние и независимо запрашивают необходимую информацию.
Этот выбор существенно влияет на то, как вы проектируете компоненты, централизация приведет только к _представительным компонентам_, а децентрализация приведет к интеллектуальным компонентам или контейнерам. Возвращаясь к аналогии губки с посудомоечной машиной, презентационные компоненты - это губки, вы можете использовать их для чего угодно: мыть машину, мыть посуду, мыть пол и т. Д. Между тем, посудомоечные машины могут мыть только посуду. , но мыть посуду в посудомоечной машине гораздо удобнее, чем губкой. Посудомоечная машина умеет мыть посуду и управляет всеми необходимыми средствами для этого (мыло, вода, сияющая жидкость). Опять же, губки можно использовать многократно, а посудомоечные машины - удобно.
Возвращаясь к централизации и децентрализации, мы можем сказать, что обе крайности практически неприменимы.
Централизация всего состояния приложения и выборки данных в одной точке приведет к суперсложному корню, передаче большого количества бесполезной информации (вниз по дереву компонентов) и кучу обработки событий. Если сделать это неправильно, это может привести к проблемам с производительностью. Допустим, компонент X должен отображать информацию Z, но изначально X должен отображать только Z.title, ему не нужно Z.content. Таким образом, корень должен сначала получить частичную версию Z, а когда происходит какое-то событие (например, щелкнуть), он должен запросить остальную часть Z. Поскольку это позволяет корню узнать о мельчайших деталях о X, возникает соблазн получить всю Z не заниматься этим, и это ухудшает производительность. Так что, как правило, вы не будете централизовать все, на самом деле большинство фреймворков SPA предложат вам распределять логику на уровне маршрута / состояния.
Полная децентрализация также невозможна, поскольку, опять же, производительность может быть ужасной. Довольно легко увидеть, что на определенном экране нескольким компонентам может потребоваться одна и та же информация, поэтому, если каждый компонент на этом экране пытается получить одну и ту же информацию, мы получаем кучу избыточных запросов. Вы можете попытаться смягчить это, используя подход Redux с кешированием во внешнем интерфейсе, я никогда не пробовал, но у меня сложилось впечатление, что он все равно сделает кучу компонентов, знающих ваше состояние, или создаст некоторую зависимость от кода управления состоянием (делая компонент менее многоразовый).
Итак, обе крайности невозможны, но у вас все еще есть некоторая свобода решать, насколько адекватна децентрализация.
Основная причина централизации заключается в том, что чем больше компонент * знает * (о состоянии и другом коде), тем сложнее его повторно использовать. Другой веский аргумент - это контроль состояния приложения и обмена данными. Если каждый компонент может управлять состоянием приложения, будет сложно поддерживать приложение, так как трудно понять, кто что и когда делает с состоянием приложения. То же самое можно сказать и о бэкэнд-коммуникациях: если каждый компонент может делать HTTP-запросы, вы можете получить кучу избыточных запросов.
С другой стороны, концентрация всего состояния и всех HTTP-запросов в корне
(весь корень страницы) обычно нарушает принцип разделения проблем.
Это также может снизить ремонтопригодность, как писал Дэн Абрамов, когда вы Приняв эту стратегию, вы в конечном итоге передадите кучу свойств дочерним компонентам. Таким образом, если вы измените интерфейс какого-либо листового компонента, вы можете в конечном итоге изменить все корневые родители, которые используют этот компонент. Это также может увеличить количество копий-вставок в приложении, если у вас есть более сложные функции, которые должны быть в большем количестве мест. Например, если у вас есть функция чата, которую можно использовать более чем на одной странице, вам необходимо реплицировать все управление состоянием и вызовы API для всех родителей, которые используют этот компонент. Если вам придется изменить эту логику, у вас снова возникнет проблема с ремонтопригодностью.
Я еще не выяснил золотую середину для этого, но кажется, что если у вас достаточно сложный и достаточно независимый (от других информация на экране), который появляется во многих местах, я бы сделал его контейнером. Эти требования сильно ограничивают компоненты, которые являются кандидатами на роль контейнеров, и большинство приложений могут жить без них (вот почему я думаю, что многие люди выступают за централизованный подход). Вот несколько примеров приложений, которые я бы хотел спроектировать как контейнеры: пользовательский интерфейс чата (например, чат Facebook или Intercom), панель поиска, возможно, создатель твита. Все они могут быть сложными и очень оторванными от экрана, который видит пользователь.
Замечания: это мой первый пост на среднем уровне, но не первый, я тестирую его на нем. Вы можете прочитать другие материалы на https://blog.sennav.com