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

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

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

4 ответа

Двухстороннее связывание данных Angular

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

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

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

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

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

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

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

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

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

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

  1. Поток данных здесь представляет собой поток событий записи - т.е. обновления состояния

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

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

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

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

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

Также см. Отличное визуальное объяснение в этом ответе: /questions/46890530/mozhet-kto-nibud-obyasnit-raznitsu-mezhdu-odnostoronnej-privyazkoj-dannyih-reacts-i-dvustoronnej-privyazkoj-dannyih-angular/46890562#46890562. Стрелки с одной и двумя головками визуально представляют односторонний и двусторонний поток данных соответственно.

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

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

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

Двухстороннее связывание

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

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

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

Заключение

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

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

Другие вопросы по тегам