Перейти к содержанию
Mercury
Русский
Дизайн книга
Меню
Русский

Reflect.3. Разделяем области состояния

Две формы могут использовать одну модель и разные значения. Provider выбирает область состояния; Reflect читает её хранилища и привязывает к ней действия.

Reflect 4.1.1 · Интерактивное упражнение

Открыть упражнение на всю страницу

Закрепите владение за приложением

Объявите модель один раз. Для каждой независимой рабочей области или запроса создайте scope и выведите компоненты внутри Provider из @fiberfx/hypergraph/hyperscript. Reflect использует существующий контекст и не вводит другую систему областей.

import {createElement as h} from "@fiberfx/hyperscript";
import {event, store, fork, dispose, scopeBind} from "@fiberfx/hypergraph";
import {Provider, setScopeMode} from "@fiberfx/hypergraph/hyperscript";
import {reflect} from "@fiberfx/reflect";

setScopeMode("required");
const added = event<void>();
const reset = event<void>();
const $count = store(0).on(added, n => n + 1).reset(reset);
const Counter = reflect({
  view: (p: {name: string; count: number; add: () => void; clear: () => void}) =>
    h("section", {"aria-label": p.name},
      h("output", null, String(p.count)),
      h("button", {onClick: p.add}, "Add"),
      h("button", {onClick: p.clear}, "Reset")),
  bind: {count: $count, add: () => added(), clear: () => reset()},
});
const left = fork();
const right = fork();
export const Example = () => h("div", null,
  h(Provider, {value: left}, h(Counter, {name: "Left"})),
  h(Provider, {value: right}, h(Counter, {name: "Right"})),
);
export const readLeft = () => scopeBind(() => $count.getState(), {scope: left})();
// The owner calls this after unmounting Example:
export const releaseScopes = () => { dispose(left); dispose(right); };

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

setScopeMode("required") заставляет общий слой привязки отклонить рендер без Provider вместо неявного чтения глобального состояния. Сам Provider этот вызов не создаёт. Вне рендера scopeBind позволяет явно прочитать нужную область. API модели описан в главе области состояния.

Поработайте с двумя панелями

Откройте эксперимент с областями. Измените имя слева и дважды увеличьте левый счётчик. Затем один раз увеличьте правый. Имена должны различаться, а счётчики — показывать 2 и 1.

Нажмите Сбросить упражнение внутри левой панели. Это сброс модели в одной области. Кнопка Начать упражнение заново внизу пересоздаёт всю сцену. Перед каждым действием предскажите, что произойдёт справа.

Проверьте и неизменённую сторону

После сброса слева ожидаются 0 и 1. Имя справа должно сохраниться. В тесте дополнительно прочитайте глобальное хранилище и убедитесь, что оно осталось в исходном состоянии: сами две панели этого не доказывают.

Связанный обработчик сохраняет исходную область. Если передать его дочернему компоненту внутри другого Provider, область обработчика не поменяется. Дочерний компонент, который сам вызывает useUnit, получит действия для того Provider, внутри которого он выведен. Замена Provider создаёт новые привязки для потомков.

Проверьте отсутствующую границу

В отрицательном тесте выведите связанный компонент без Provider при включённом required-режиме. Общий слой привязки должен отклонить рендер. Делайте это в отдельном тесте, не ломая рабочую сцену.

Прямой вызов события вне связанного обработчика тоже требует внимания: наличие Provider где-то на странице не привязывает этот вызов к области. Вызывайте действия через bind, useUnit или явный scopeBind. Не обещайте сохранение контекста через любые сторонние асинхронные вызовы: тест Reflect проверяет конкретно ожидание эффекта Hypergraph.

Выберите нужный сброс

Сначала сбросьте одну панель и убедитесь, что соседняя сохранила данные. Затем начните всё упражнение заново: обе панели должны вернуться к началу. В своём приложении разделяйте «очистить форму» и «закрыть рабочую область»: первое меняет значения, второе завершает владение ресурсами.

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

Изолируйте второй редактор

Выведите два редактора разных документов на одной модели. Дайте каждому свою область и свяжите действие сохранения через Reflect. Проверяйте неизменность соседнего редактора так же внимательно, как изменение целевого.

На сервере не храните область запроса в общей переменной модуля. Создавайте отдельную область на запрос и освобождайте её на границе владельца. В следующей главе появятся коллекции внутри области: scope разделяет рабочие пространства, а ключ — строки одного пространства.

Назад · Курс · Далее