Повесть об однонаправленном потоке данных в Angular
Когда дело доходит до Angular, у фреймворка есть свои преимущества и особенности. В то время как React реализует шаблон однонаправленного потока данных по умолчанию, Angular точно не пошел по этому пути с самого начала.
Однонаправленный поток данных - это концептуальный шаблон, который используется многими фреймворками и библиотеками во внешнем интерфейсе, который недавно был популярен благодаря появлению шаблонов Redux за последние несколько лет.
Но что именно представляет собой однонаправленный поток данных, какое отношение он имеет к неизменности и почему он великолепен в Angular?
Правда об однонаправленном потоке данных
Однонаправленный поток данных - это не то слово, которое мы часто видим, и это не то, что органично встречается в разговорах. Тем не менее, это аккуратный небольшой шаблон управления данными, который может упростить реакцию вашего приложения на изменения.
Для большинства приложений все в конечном итоге сводится к данным. Поток данных между различными уровнями, такими как представления, компоненты и сервисы, может определять эффективность модульности приложения по мере его роста.
Так что же такое однонаправленный поток данных?
Однонаправленный поток данных - это программный паттерн, который имеет дело с тем, как обновляются данные. В настоящее время используются два основных шаблона - однонаправленный и двунаправленный. Единой частью однонаправленного относится к идее, что данные могут передаваться только в одном направлении.
Для внешнего интерфейса после того, как представление было визуализировано, требуется действие для изменения данных и повторного рендеринга всего или части представления с нуля.
React делает это по умолчанию, и нет доступной явной привязки, позволяющей обновлять представление без прямого действия со стороны уровней под ним.
Обновления происходят в одном направлении и только. Данные не должны изменяться и поэтому считаются неизменными. Когда что-то происходит и происходит изменение, это состояние больше не существует, и оно рассматривается новым объектом как объект.
Изменение вызвано внешним действием. Когда это происходит, представление стирается и перерисовывается с новыми данными. В двух словах, это однонаправленный поток данных: односторонний поток данных, в котором данные могут перемещаться только в одном направлении и не могут возвращаться в том направлении, откуда они только что пришли.
При однонаправленном потоке данных нет необходимости отслеживать состояния, потому что изменение данных приведет к полному изменению представления.
Гипотетический однонаправленный поток данных
Чтобы понять это в контексте Angular, нам нужно вернуться назад во времени - к первоначальной итерации Angular.js.
Небольшая предыстория
В Angular привязки обновлений к представлению происходят во время обнаружения изменений. При обнаружении изменений изменения данных у дочерних компонентов также могут обновить родительский, а не оставаться изолированными. Это похоже на реализацию шаблона обратного наследования, который позволяет родительским компонентам брать значения и свойства у своих дочерних компонентов.
На уровне поверхности изменения в представлении могут выглядеть одинаково как для двунаправленного, так и для однонаправленного потока данных. Однако на уровне отношений данных двунаправленный подход может быть несколько проблематичным.
Гипотетический однонаправленный поток данных
В Redux данные помещаются в единое логическое пространство, которое имеет стандартизированный метод доступа и изменения. Действия необходимы для того, чтобы что-то сделать с данными или получить их. Эта модель эффективна и растет в популярности, потому что данные централизованы и могут быть изменены только в одном месте, а не мутированы несколькими компонентами.
В Angular.js (он же Angular 1) двусторонняя привязка упрощает перемещение данных между различными частями приложения. Однако это создает серьезную проблему, когда компоненты начинают работать нежелательным образом из-за побочных эффектов двунаправленного потока данных.
Гипотетическая схема Angular.js потока данных компонентов
На диаграмме выше у нас есть гипотетическое приложение с родительским компонентом, отображающим два других дочерних компонента. Переменная cat вызывается для внешнего интерфейса и отображается. В этом случае значением является Тибберс. Однако с двунаправленным подходом к потоку данных все может пойти наперекосяк.
Гипотетическая диаграмма того, как двунаправленный поток данных может быть проблематичным
На приведенной выше диаграмме, когда переменная cat изменяется на Bob, данные возвращаются обратно в том же направлении, что и вниз, создавая обратный каскадный эффект для отображаемых данных. Возможно, вы не хотели, чтобы родительские компоненты Child 2 обновляли данные.
Вот расширенный пример, когда двунаправленный поток данных становится беспорядочным по мере роста приложения.
Гипотетический пузырьковый эффект за счет двунаправленного потока данных
На диаграмме выше, если дочерний элемент 2 изменится, будут затронуты оба родительских компонента, даже если они не зависят друг от друга. Данные, которые должны быть изолированы, становятся взаимосвязанными. Это проблема, потому что по мере роста приложения появляется больше потенциальных точек изменения и, следовательно, больше потенциальных точек отказа.
При однонаправленном подходе каждый компонент разделяется, и состояния становятся контейнерами. Невозможность передачи данных обратно создает линейный путь для изменения.
Хотя двунаправленный подход облегчает жизнь, поскольку вам не нужно явно провоцировать изменения с помощью действий, он не так легко масштабируется, как однонаправленный подход.
Но разве нельзя реализовывать двунаправленный подход в Angular 2+?
Уже нет! Двусторонняя привязка отличается от двунаправленного потока данных. Angular 2+ теперь реализует однонаправленный поток данных - это означает, что представление не может быть обновлено после его составления.
Каждый раз, когда представление визуализируется, Angular проходит жизненный цикл создания, проверки, создания и уничтожения представления. Это означает, что представление по существу «перекрашивается» каждый раз, когда что-то меняется.
Мы не видим, чтобы это произошло из-за того, как быстро это происходит, и изменение ощущается почти мгновенно.
Двусторонняя привязка относится к связи между службой и ее связанным представлением. Двунаправленный и однонаправленный поток данных относится к границам, областям и направлениям перемещения данных между сервисами и представлениями.
Связывание относится к единичным отношениям один-один-один, в то время как двунаправленное и однонаправленное относится к отношениям между компонентами.
концептуальная схема двустороннего связывания с однонаправленным потоком данных и двунаправленным потоком данных
Заключительные слова
Направление потока данных часто путают с концепцией двустороннего связывания. Это потому, что оба понятия связаны с данными.
Однонаправленный поток больше связан с данными и тем, как они взаимодействуют с другими компонентами на основе их отношений друг с другом. Двусторонняя привязка более ограничена представлением и его взаимодействием со связанными компонентами обслуживания.
Понимание того, как работает поток данных, поможет вам понять, почему что-то идет не так и где они идут не так. Реализация шаблона однонаправленного потока данных в Angular означает, что наследовать могут только дочерние компоненты. Родители больше не оставляют за собой это право.
Иногда это может вызвать проблемы, если вы хотите, чтобы данные передавались в обратном направлении по любой причине. Вот почему для централизации данных часто используется шаблон избыточности, в то же время поддерживая однонаправленный поток данных.
В Redux данные отделяются от компонента и помещаются в единое пространство с помощью стандартного метода поиска и изменения. Это означает, что наследование обратного потока больше не является проблемой, поскольку данные извлекаются из одного хранилища, а не из дочерних элементов.
Это также означает, что данные могут совместно использоваться компонентами без необходимости нарушать правила границ и передавать данные. Нет необходимости в трассировке - просто подключение к центральному хранилищу.