Skip to content

Отслеживание query

router.trackQuery связывает query-параметры URL с событиями модели. Это нужно, когда часть интерфейса хранится в строке запроса: диалог, фильтр, вкладка, сортировка или состояние встроенного виджета.

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

API трекера

ts
interface QueryTracker<Parameters> {
  entered: Event<Parameters>;
  exited: Event<void>;
  enter: EventCallable<Parameters>;
  exit: EventCallable<{ ignoreParams: string[] } | void>;
}

parameters принимает любой объект с safeParse:

ts
interface QuerySchema<T> {
  safeParse(query: Query):
    | { success: true; data: T }
    | { success: false };
}

Роутер не требует Zod. Можно использовать Zod, Valibot, свой парсер или маленькую inline-схему.

Диалог в query

Частый сценарий — диалог, который открывается через query:

ts
const inviteDialog = router.trackQuery({
  forRoutes: [teamRoute],
  parameters: {
    safeParse(query) {
      return query.dialog === "invite"
        ? { success: true, data: { dialog: "invite" as const } }
        : { success: false };
    },
  },
});

Открыть и закрыть диалог можно через tracker:

ts
inviteDialog.enter({ dialog: "invite" });
inviteDialog.exit();

entered срабатывает, когда query подходит под схему и один из forRoutes открыт. exited срабатывает, когда query больше не подходит или приложение уходит с этих роутов.

Фильтры

Фильтры удобно читать из query, чтобы перезагрузка страницы сохраняла состояние:

ts
const issueFilter = router.trackQuery({
  forRoutes: [issuesRoute],
  parameters: {
    safeParse(query) {
      const status = query.status;

      return status === "open" || status === "closed"
        ? { success: true, data: { status } }
        : { success: false };
    },
  },
});

reaction({
  on: issueFilter.entered,
  run({ status }) {
    issues.status.value = status;
    void issues.loadFx();
  },
});

Записать фильтр в URL:

ts
issueFilter.enter({ status: "open" });

Закрыть и оставить часть query

По умолчанию exit() очищает query:

ts
inviteDialog.exit();

Если закрытие одного состояния не должно стереть другое, передается список параметров, которые надо оставить:

ts
inviteDialog.exit({ ignoreParams: ["tab", "sort"] });

Ручная проверка

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

ts
const refreshed = event<void>();

const preview = router.trackQuery({
  check: refreshed,
  parameters: previewSchema,
});

Это полезно, если парсер дорогой или host-страница меняет query часто, а модель не должна реагировать на каждое изменение.