Tribute to React: введение контейнеров и компонентов представления в Vue

внешний интерфейс Vue.js React.js Vuex
Tribute to React: введение контейнеров и компонентов представления в Vue

Если вы использовали Redux для разработки React, вы, должно быть, слышали о компонентах Smart/Container или Dumb/Presentational Components. Каковы преимущества этого разделения? Можем ли мы научиться из этого разделения писать Vue? Что насчет кода? Этот пост покажет, почему мы должны использовать этот шаблон и как написать оба компонента на Vue.

Зачем использовать контейнерные компоненты?

Если мы хотим написать компонент для отображения комментариев, прежде чем мы услышим о компонентах-контейнерах, наш код обычно пишется так:

components/CommentList.vue

为 Vue 引入容器组件和展示组件

store/index.js

为 Vue 引入容器组件和展示组件

Кажется естественным писать так, есть ли проблема или можно оптимизировать?

Существует очевидная проблема, потому что CommentList.vue связан с хранилищем Vuex проекта, что затрудняет повторное использование из текущего проекта.

Есть ли лучший способ организовать компоненты, которые могут решить эту проблему? Пришло время понять концепцию компонентов-контейнеров в сообществе React.

Что такое контейнерный компонент

На React.js Conf 2015 былоMaking your app fast with high-performance componentsтема знакомит с компонентами контейнера.

什么是容器组件

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

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

Разница между компонентами-контейнерами и компонентами представления

Компоненты дисплея компонент контейнера
эффект Опишите, как визуализировать (скелет, стиль) Опишите, как это работает (извлечение данных, обновление статуса)
использовать магазин напрямую нет да
Источники данных props Слушайте состояние магазина
модификация данных Вызов функции обратного вызова из реквизита отправка действий в магазин

Из документации Redux https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/5/2/1631f590aa5512b7~tplv-t2oaga2asx-image.image

Модифицируйте приведенный выше пример с помощью шаблона компонента контейнера/компонента представления.

Для исходного примера, как быстро разделить компоненты по этому шаблону? Мы в основном разделились на CommentList.vue, в первую очередь на базовый дизайн:

Эскизный дизайн

Компоненты дисплея

  • components/CommentListNew.vueЭто новый компонент отображения комментариев для отображения комментариев.
    • comments: Arrayопора получает как{ id, author, body }Массив элементов комментариев для отображения в виде файлов .
    • fetch()Способ получения обновленных данных комментариев

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

Эти реквизиты, такие как комментарии и выборка, не имеют значения, предоставляются ли они Vuex.Вы можете использовать Vuex или другие библиотеки управления состоянием или даже EventBus, чтобы повторно использовать эти компоненты отображения.

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

компонент контейнера

  • containers/CommentListContainer.vueПодключить компонент CommentListNew к магазину

Компонент-контейнер может инкапсулировать состояние или действие, соответствующее хранилищу, в компонент отображения.

Реализация кодирования

Talk is cheap, show me the code!

components/CommentListNew.vue

Этот файл больше не зависит от хранилища и вместо этого передается из реквизита.

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

为 Vue 引入容器组件和展示组件

containers/CommentListContainer.vue

Обязанности компонентов контейнера

  • Получите обновление состояния через вычисление и передайте его компоненту дисплея.
  • Функция обратного вызова определяется через методы, а функция обратного вызова внутренне вызывает метод отправки хранилища и передает его компоненту отображения.

为 Vue 引入容器组件和展示组件

Реализация компонентов контейнера с использованием @xunlei/vuex-connector

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

Недостатки ручной реализации компонентов контейнера

Код более сложный

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

Невозможно передать другие реквизиты компоненту отображения

Например, к компоненту отображения добавляется новый реквизит с именем type, который может передавать тип комментария, чтобы различать, является ли он популярным или последним.Если используется описанный выше метод реализации контейнера, сначала необходимо создать новый реквизит с именем type. добавлен в слой компонента контейнера для приема внешних параметров передачи, а затем определить свойство с именем type внутри компонента отображения, а затем передать его дальше.

Реквизиты, которые должны быть прозрачно переданы, должны быть определены дважды, что увеличивает стоимость обслуживания.

为 Vue 引入容器组件和展示组件

为 Vue 引入容器组件和展示组件

Компоненты контейнера не могут быть оптимизированы единообразно

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

Невозможно управлять компонентом отображения, чтобы не получить магазин

Поскольку компонент-контейнер получает хранилище через this.$store, компонент отображения может напрямую взаимодействовать с хранилищем.Если ограничений нет, трудно единообразно потребовать, чтобы компонент отображения не взаимодействовал напрямую с хранилищем.

Используйте @xunlei/vuex-connector

@xunlei/vuex-connector опирается на метод подключения реакции редукции и разрабатывается на основе vuex.

Имеет следующие характеристики:

Код очень лаконичный

Вот модифицированная версия компонента контейнера, реализованного вручную в приведенном выше примере:

comonents/ConnectCommentListContainer.vue

为 Vue 引入容器组件和展示组件

Через метод connnect коннектора передается конфигурация, которую нужно сопоставить. Он поддерживает mapStateToProps, mapGettersToProps, mapDispatchToProps, mapCommitToProps, для каждого из которых требуется только настроить простую функцию сопоставления или строку.

Затем передайте компонент дисплея, который нужно подключить в возвращаемой функции, это очень лаконично?

Сами компоненты контейнера также можно использовать повторно.

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

Например:

Если вы написали несколько версий компонента отображения комментариев, принятые данные и способ обновления данных одинаковы, то вам не нужно создавать компонент-контейнер для каждой версии компонента комментариев, если вы повторно используете тот же высокоуровневый компонент Подойдет функция компонента первого порядка.

Вопрос, что за разъем?

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

为 Vue 引入容器组件和展示组件

Программу Vue на самом деле нужно инициализировать только один раз.

Поддерживает передачу других реквизитов для отображения компонентов

VuexConnector реализован с использованием функциональных компонентов (functional: true )

Функциональные компоненты не имеют состояния (нет реактивных данных), нет экземпляра (нет этого контекста).

Функциональные компоненты очень полезны в качестве компонентов-оболочек, например, когда вам нужно сделать:

  • Программно выберите один из нескольких компонентов
  • Манипулируйте дочерними элементами, реквизитами, данными, прежде чем передавать их дочерним компонентам.

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

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

Унифицированная упаковка облегчает последующую унифицированную оптимизацию

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

Может управлять компонентом презентации, не может напрямую связываться с магазином

VuexConnector полагается не на this.$store, а на инициализацию входящего экземпляра хранилища.Компонент-контейнер может использовать соединение для подключения компонента отображения к хранилищу.

Поскольку мы не полагаемся на this.$store, нам не нужно передавать экземпляр хранилища, когда мы вводим новый Vue в программу.

Например, раньше мы инициализировались следующим образом:

为 Vue 引入容器组件和展示组件

После использования VuexConnector нет необходимости или лучше не передавать хранилище при инициализации нового Vue, чтобы избежать проблемы связывания кода, вызванной потоком this.$store.

Преимущества введения шаблона компонента контейнера/компонента представления

возможность повторного использования

Разделение компонентов-контейнеров/компонентов-дисплеев основано на принципе единой ответственности: компонент-контейнер отвечает за связь с магазином, а компонент дисплея отвечает только за отображение, что разделяет компоненты и обеспечивает лучшее повторное использование.

прочность

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

Кроме того, валидацию реквизитов можно выполнить следующими способами:

Проверка реквизитов компонента Vue

Вы можете проверить тип реквизита. По умолчанию вы можете проверить, относится ли он к следующему типу:

  • String
  • Number
  • Boolean
  • Function
  • Object
  • Array
  • Symbol

Если ваши реквизиты являются экземпляром класса, type также может быть пользовательской функцией-конструктором, использующей определение instanceof.

Если он по-прежнему не соответствует требованиям, вы можете настроить функцию проверки:

为 Vue 引入容器组件和展示组件

Система типов TypeScript

Проверка реквизитов компонента Vue по-прежнему не очень удобна для объектов или другой сложной проверки типов, поэтому многие люди также рекомендуют, чтобы реквизиты всех были как можно более простыми, но если вы разрабатываете приложения Vue с помощью TypeScript, вы можете использовать статическую проверку типов TypeScript для объявить свой реквизит.

为 Vue 引入容器组件和展示组件

Тестируемость

Тестирование также упрощается, поскольку компоненты выполняют меньше работы.

Компоненты-контейнеры не заботятся об отображении пользовательского интерфейса, они заботятся только о данных и обновлениях.

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

Ограничения, вызванные введением шаблона компонента контейнера/компонента представления

Стоимость обучения и развития

Из-за разделения компонентов контейнера/компонентов отображения на начальном этапе будут добавлены некоторые затраты на обучение, но когда вы прочитаете эту статью, вы в основном начнете.

Во время разработки, поскольку вам нужно инкапсулировать контейнер и упаковать некоторые данные и интерфейсы для отображения компонентов, это увеличит рабочую нагрузку. @xunlei/vuex-connector может значительно уменьшить вашу рабочую нагрузку за счет настройки.

Кроме того, объявление свойств внутри презентационного компонента требует небольшой работы.

В целом, соотношение ввода-вывода при введении режима компонента-контейнера/компонента-дисплея вполне оправдано.

дальнейшее чтение

пример кода

Демонстрация шаблона компонента Vue Vuex Container-Show

Демонстрационный онлайн-адрес:

Thunder Wind 2 Oh.GitHub.IO/v UE-v u ex-co…

Исходный код демо:

GitHub.com/Thunderwind 2 О/В…

@xunlei/vuex-connector

Vuex store Connector на основе экологической реализации Vue

Исходный код @xunlei/vuex-connector:

GitHub.com/Thunderwind 2 О/В…

Добро пожаловать в Звезду

Пролистайте и обратите внимание на внешний публичный аккаунт Xunlei.

автор: бинггг

вычитка: Джиалан