События приложения

App Events позволяют частям приложения общаться, не будучи связанными напрямую: одно место объявляет о событии, другое на него реагирует.

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

События решают это иначе. Любая часть приложения объявляет именованное событие — при необходимости с данными, — а любая другая на него подписывается. Отправитель и получатель друг о друге не знают.

Пример: пользователь добавил товар в корзину из карточки. Вместо того чтобы вручную обновлять все места, где показано состояние корзины, приложение объявляет событие CartUpdated. Счётчик на значке, мини-корзина и список товаров подписаны на него и обновляются сами. Карточка товара при этом понятия не имеет, кто на неё среагирует.

app-event.avif

Из чего это состоит

События

Событие — именованный сигнал о том, что что-то произошло:

  • Internet Connection Changed — изменилось состояние сети;
  • Cart Updated — товар добавлен в корзину или удалён из неё.

Вместе с событием передаются данные. Скажем, Cart Updated может нести сведения о конкретном товаре. Структура этих данных описывается типом данных FlutterFlow.

Обработчики

Обработчик определяет, что произойдёт при событии. Когда событие срабатывает, обработчик выполняет свой Action Block.

Глобальные и локальные

Область события определяет, где оно обрабатывается и кто может на него ответить. Глобальные обрабатываются на уровне приложения, локальные — теми страницами и компонентами, которые на них подписались.

ГлобальныеЛокальные
Где обрабатываютсяНа уровне приложенияНа страницах и в компонентах, которые явно подписались
Сколько обработчиковРовно один — назначенный Action BlockСколько угодно: подписаться может любая страница или компонент
ПодпискаАвтоматическая, всегда активнаРучная: добавляется и снимается действиями
Для чегоОбщие для всего приложения вещи: аналитика, логи, состояние авторизации, глобальные уведомленияРеакции конкретных экранов: обновить список, перерисовать виджет, синхронизировать вкладки
ОбработкаПоследовательная очередь — по одному за разШироковещательная — все подписчики получают событие сразу

Действия

Событиями управляют три действия:

  • Trigger App Event — объявить событие. Доступно везде, где есть действия: на нажатии кнопки, при загрузке страницы, внутри потока действий.
  • Add Local App Event Handler — подписать текущую страницу или компонент на локальное событие.
  • Cancel Local App Event Handler — отписаться от него.

Как пользоваться

1. Создать событие

  1. Откройте страницу App Events в меню слева.
  2. Нажмите +.
  3. Введите имя события.
  4. Настройте его:
    • Description — зачем нужно событие; попадёт комментарием в сгенерированный код Dart.
    • ScopeGlobal или Local.
    • Include Event Data — передаются ли вместе с событием данные.
    • Data Type — тип, описывающий структуру этих данных.
    • Nullable — могут ли данные быть null.
  5. Для глобального события назначьте обработчик — Action Block. Если событие несёт данные, у блока должен быть параметр соответствующего типа.

2. Объявить событие

  1. Откройте Action Flow Editor там, где событие должно объявляться.
  2. Добавьте действие Trigger App Event из группы App Events.
  3. Настройте его:
    • Event to Trigger — созданное событие.
    • App Event Data — значения, которые уйдут вместе с событием.
    • Wait for Completion (только для глобальных, включено по умолчанию) — ждать ли завершения обработчика, прежде чем брать следующее событие из очереди. Выключите, если ответ не важен.
    • Debug ID — метка, по которой при отладке видно, откуда событие пришло.

3. Обработать событие

Глобальные

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

Локальные

  1. На странице или в компоненте, который должен реагировать, откройте Action Flow Editor — обычно на триггере On Page Load или On Component Load.
  2. Добавьте действие Add Local App Event Handler.
  3. Настройте:
    • Local App Event to Handle — нужное событие.
    • Handler Action Block — что выполнить. Если событие несёт данные, у блока должен быть параметр соответствующего типа.

Если подписку нужно снять раньше времени — например, по переключателю в настройках, — добавьте действие Cancel Local App Event Handler для того же события.

совет

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

Примеры

Состояние сети (глобальное событие)

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

Обработчик может:

  • показать плашку «Нет соединения», когда связь пропала;
  • убрать её, когда связь вернулась;
  • приостановить и возобновить фоновую синхронизацию.

Вместе с событием удобно передавать подробности:

  • isConnectedtrue / false
  • connectionTypewifi / mobile / none

global-event.avif

Полная настройка:

  1. Создайте тип данных ConnectivityStatus с полями:
    • isConnected (Boolean)
    • connectionType (String) — wifi, mobile или none
  2. Создайте глобальное событие Internet Connection Changed:
    • Scope: Global
    • Include Event Data: включено
    • Data Type: ConnectivityStatus
  3. Создайте Action Block handleConnectivityChange, который:
    • смотрит на isConnected;
    • показывает плашку «Нет соединения» при false;
    • при желании показывает текущий connectionType;
    • убирает плашку при восстановлении связи.
  4. Объявляйте событие при каждом изменении:
    • из слушателя сети или собственного действия — Trigger App Event;
    • при наличии связи передавайте isConnected: true и connectionType: wifi или mobile;
    • при её отсутствии — isConnected: false и connectionType: none.

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

Синхронизация вкладок (локальное событие)

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

Подписанные вкладки могут:

  • перезапросить данные;
  • обновить сводки и графики;
  • перезагрузить списки и таблицы.

Событие локальное, поэтому отреагируют только подписавшиеся.

local-event.avif

Полная настройка:

  1. Создайте локальное событие Dashboard Data Changed:
    • Scope: Local
    • Include Event Data: выключено
  2. На каждой вкладке-компоненте, обычно на On Component Load:
    • добавьте Add Local App Event Handler;
    • выберите событие DashboardDataChanged.
  3. Создайте Action Block refreshDashboardTab, который:
    • перезапускает запросы к бэкенду;
    • обновляет зависящие от них виджеты.
  4. В действии сохранения внутри любой вкладки:
    • добавьте Trigger App Event;
    • выберите DashboardDataChanged.

После этого все подписанные вкладки обновляются сами.

Как события обрабатываются

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

flow.avif

Что важно помнить:

  • Глобальные события обрабатываются последовательно. Несколько объявленных подряд событий выполнятся друг за другом, а не одновременно.
  • Локальные события рассылаются всем активным подписчикам сразу.
  • Wait for Completion (только для глобальных, включено по умолчанию) заставляет очередь дождаться завершения обработчика. Выключите, если ждать не нужно.
  • Глобальный обработчик срабатывает всегда, откуда бы событие ни пришло.
  • Локальные обработчики живут, пока жива их страница или компонент; при закрытии подписка снимается сама.

Что стоит учесть

Глобальное или локальное

Глобальное — когда:

  • реакция нужна везде, независимо от открытого экрана: снекбары, смена состояния авторизации, логирование;
  • логику удобнее держать в одном месте;
  • поведение общее для всего приложения.

Локальное — когда:

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

Коротко: глобальные — про приложение целиком, локальные — про конкретный экран.

Имена

Называйте события в прошедшем времени — по тому, что уже произошло, а не что нужно сделать:

  • User Logged In, а не Login
  • Cart Updated, а не Update Cart
  • Payment Completed, а не Process Payment

Тогда поток действий читается как фраза: «когда сработало Cart Updated, обновить список товаров».

инфо

Из имени FlutterFlow сам собирает идентификатор в camelCase — он используется в коде:

  • User Logged InuserLoggedIn
  • Cart UpdatedcartUpdated
  • Payment CompletedpaymentCompleted

Один обработчик — одна задача

Каждый Action Block должен делать что-то одно. Так поток событий остаётся читаемым.

Если реакций нужно несколько:

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

Не выстраивайте цепочки

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

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

Пользуйтесь Debug ID

Поле Debug ID в действии Trigger App Event помечает место, откуда событие объявлено. Когда одно и то же событие объявляется из нескольких мест, без этого поля разбираться тяжело.

Частые вопросы

Почему появляется «No local app events available to handle»?

Сообщение появляется при добавлении действия Add Local App Event Handler, если:

  • ни одного события с областью Local не создано;
  • для всех доступных локальных событий обработчик на этой странице или в этом компоненте уже добавлен.

Что делать: создайте событие с областью Local или проверьте, нет ли уже обработчика для нужного события.

Почему появляется «No local app event handlers available to cancel»?

Значит, на текущей странице или в компоненте нет активных локальных обработчиков.

Что делать: сначала добавьте обработчик действием Add Local App Event Handler — отменять пока нечего.

Почему не срабатывает глобальный обработчик?

Проверьте:

  • область события — Global;
  • в настройках события назначен Handler Action Block;
  • параметры Action Block совпадают с типом данных события, если событие их несёт.

Почему не срабатывает локальный обработчик?

Проверьте:

  • действие Add Local App Event Handler действительно выполняется — например, стоит в On Page Load или On Component Load;
  • область события — Local: глобальные в списке локальных обработчиков не появляются;
  • страница или компонент, который слушает событие, всё ещё открыт.

Почему события срабатывают не в том порядке?

События проходят через очередь. Пока Wait for Completion включено, каждое обрабатывается до конца, прежде чем начнётся следующее.

Если порядок сбивается, проверьте, не выключено ли Wait for Completion у части триггеров — тогда следующее событие стартует, не дожидаясь завершения предыдущего.

И помните: очередь есть только у глобальных событий. Локальные рассылаются подписчикам сразу и в очередь не попадают.

перевод официальной документации FlutterFlow

обновлено

ESC