Двунаправленная привязка данных (Angular) против однонаправленного потока данных (React/Flux)

На прошлой неделе я пытался понять, чем отличаются двусторонняя привязка данных (Angular) и односторонняя передача данных (React/Flux). Они говорят, что односторонний поток данных является более мощным и более легким для понимания и отслеживания: он является детерминированным и помогает избежать побочных эффектов. В моих глазах новичка они оба выглядят примерно одинаково: представление слушает модель, а модель реагирует на действия, выполненные с представлением. Оба утверждают, что модель является единственным источником правды.

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

Ответ 1

В Angular у вас много контроллеров. Одним из примеров может быть пользователь, запускающий действие над View 1, которым управляет контроллер 1. Контроллер 1 выполняет что-то, но также запускает событие, которое попадает другим контроллером 2. Контроллер 2 обновляет некоторое свойство в области $scope, а View 2 внезапно изменилось.

Внезапная операция над View 1, обновленный вид 2. Если теперь мы добавим некоторые обратные вызовы Async и немного больше цепочек событий, вы можете больше не знать точно, когда/как ваши представления обновляются.

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

Ответ 2

Скажем, ваше приложение - это просто поток мастера, но он имеет несколько сложных взаимодействий, т.е. один шаг может изменить поведение следующего шага.

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

Как отладка будет работать на двустороннюю привязку и одностороннюю привязку?

Двусторонняя привязка

Я бы начал проверять, какое поведение отличается и с какой-то удачей, перейти к той же точке, что и пользователь, и определить ошибку. Но в то же время может быть какое-то странное взаимодействие между различными частями приложения. У меня может быть некоторая привязка данных, которая неверна (например, репликация состояния модели, но не привязка) или другая странная сложность между компонентами, которые трудно отлаживать. Возможно, будет сложно выделить ошибку.

Односторонняя привязка

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

Заключение

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

Даже это не сработает, вы также можете регистрировать действия. Например, AFAIR не является простым способом отслеживать все действия, изменяющие состояние, на Angular. С Redux это довольно, довольно легко.

Ответ 3

  • Поток данных - это поток событий write, то есть обновление состояния

  • Эти события текут между представлениями и контроллерами (и такими службами, как HTTP-серверы)

  • Односторонний поток - это в основном гигантский цикл:

    • app view использует (читает, а не пишет) состояние приложения для рендеринга
    • когда приложение получает какие-то стимулы извне (пользователь вводил какой-либо текст в поле ввода или результат HTTP-запроса пришел), он выдает событие write - или в сленге Redux/Flux отправляет действие
    • все события, от всех контроллеров и представлений, вливаются в единую функцию приемника-приемника (редуктор); хотя характер диспетчерской функции позволяет ей состоять из более простых функций отправки, концептуально существует только один диспетчер для всего приложения. Диспетчер
    • использует событие, чтобы выяснить, какая часть состояния должна быть обновлена.
    • перейти к началу
  • Двусторонний поток aka привязка данных связывает два состояния: в большинстве случаев один внутри контроллера (например, некоторая переменная) и один внутри вид (например, содержимое текстового поля). Связывание означает, что, когда одна часть изменяется, другая часть изменяется также и получает одно и то же значение, поэтому вы можете притворяться, что есть только одна часть государства (в то время как есть две на самом деле). Запись происходит между контроллерами и представлениями - таким образом двусторонний.

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

  • Односторонний поток данных остывает, когда вы можете использовать этот дополнительный объект - поток событий. И, как правило, вы можете - это полезно для Undo/Redo, повторения действий пользователя (например, для отладки), репликации и т.д. И т.д. И код для поддержки этого намного проще и обычно может быть написан на простом JavaScript структурного синтаксиса. С другой стороны, поскольку у вас больше нет привязки данных, он больше не сохраняет вам какой-либо шаблон.

Кроме того, см. большое визуальное объяснение в этом ответе: fooobar.com/questions/101474/.... Одноглавые и двуглавые стрелки визуально представляют односторонний и двухсторонний поток данных соответственно.

Ответ 4

Угловая двусторонняя привязка данных

Это стало возможным благодаря механизму, который синхронизирует вид и модель при любом изменении. В Angular вы обновляете переменную, а механизм обнаружения изменений позаботится об обновлении представления и наоборот. В чем проблема? Вы не контролируете механизм обнаружения изменений. Мне пришлось прибегнуть к ChangeDetectorRef.detectChanges или NgZone.run, чтобы принудительно обновить представление.

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

Реагировать на односторонний поток данных

Это означает, что представление всегда получает свое состояние из модели. Чтобы обновить представление, необходимо сначала обновить модель, а затем перерисовать представление. React делает процесс перерисовки представления чрезвычайно эффективным, поскольку он сравнивает не реальный DOM, а виртуальный DOM, который хранится в памяти. Но как обнаружение изменений работает в этой динамике? Ну, вы запускаете это вручную.

В React вы устанавливаете новое значение состояния, которое затем вызывает ReactDOM.render, который вызывает процесс сравнения/обновления DOM. В React/Redux вы отправляете действия, которые обновляют хранилище (единственный источник правды), а затем остальные. Дело в том, что вы всегда знаете, когда что-то меняется, и что стало причиной изменений. Это делает решение проблем довольно простым. Если ваше приложение зависит от состояния, вы просматриваете его до и после действия, которое вызвало изменение, и убедитесь, что переменные имеют значение, которое они должны.

Реализации в сторону

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

Ответ 5

Архитектура Angular устанавливает динамический механизм для потока данных посредством использования двух путей (двусторонняя привязка данных) между представлением и моделью. Механизм двустороннего связывания данных позволяет связать свойство с событием через директиву NgModel в форме с использованием простой записи. Таким образом, шаблоны и компоненты синхронизируются с любым изменением данных. Этот обмен данными также может обеспечить двустороннюю связь между родительским и дочерним компонентами. В этом случае должно быть два свойства в дочернем компоненте, один вход и один выход.

React представляет архитектуру для управления потоком данных в одном направлении сверху вниз (нисходящий или однонаправленный поток данных). Этот шаблон сравнивается с каскадом реквизита в дереве компонентов, в котором между ними установлена определенная иерархия. Родительские компоненты могут передавать свои состояния (состояния, т.е. переменные данные) или функции как свойства (реквизиты) своим дочерним компонентам. Они в свою очередь могут только читать данные своих родителей, но не изменять их. Тем не менее, они смогут делать обратные вызовы для родителей в иерархическом порядке. Который в соответствии с полученным обратным вызовом изменит данные и направит их компоненту сына, который сделал вызов.

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

Если вам нужно больше подробностей по этому вопросу, вы можете посетить эту статью: Сравнение между React, Angular и Vue - Часть II