Skip to content

PlatformContext

Всё, что ваш модуль знает о платформе, приходит через один объект: PlatformContext. Оболочка внедряет его; вы используете его через React-хуки.

Форма

ts
interface PlatformContext {
  user: PlatformUser;                  // кто вошёл + его роли в realm
  organization: PlatformOrganization;  // арендатор + его лицензированные модули
  building: PlatformBuilding | null;   // активное здание — null на уровне организации
  locale: string;                      // "en", "ru", "hi"
  theme: 'light' | 'dark';
  api: PlatformApiClient;              // предварительно аутентифицированный HTTP-клиент в области арендатора
  eventBus: EventBusClient;            // публикация / подписка на события платформы
}

Обратите внимание: building может быть null — пользователь может находиться на уровне организации, не выбрав здание. Используйте useBuilding(), когда маршрут действительно требует здания, и useOptionalBuilding(), когда нет.

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

Хуки

tsx
import {
  usePlatformContext,
  useBuilding,
  useCurrentUser,
  useOptionalBuilding,
} from '@tv/extension-sdk/react';

function MyComponent() {
  const ctx = usePlatformContext();     // весь контекст; бросает исключение вне провайдера
  const building = useBuilding();        // бросает исключение, если здание не выбрано
  const user = useCurrentUser();         // вошедший пользователь
  const maybe = useOptionalBuilding();   // null вместо исключения
}

Ререндеры — сколько стоит подписка

PlatformContext — настоящий React-контекст, поэтому применимо стандартное опасение: при смене значения провайдера перерисовываются все подписчики. Здесь оно ограничено самой конструкцией:

  • Identity значения стабильна — оболочка держит один объект контекста и заменяет его только при смене вошедшего пользователя, выбранного здания, локали или темы. Всё это редкие, инициированные пользователем моменты; первые три и так обесценивают всё, что модуль отрисовал.
  • Переключение темы — точечный патч, а не пересборка. Оболочка обновляет поле theme в объекте контекста, сохраняя всё остальное: подписчики перерисовываются один раз с новым значением, соединения не рвутся. Модулям, которые красятся через CSS-переменные, ctx.theme вообще не нужен; читайте его только для поверхностей, рисуемых из JS (canvas, материалы Three.js).
  • Высокочастотные данные через значение контекста не текут. Телеметрия и события платформы приходят колбэками eventBus.subscribe() — шквал событий перерисует только компоненты, чьё состояние вы сами обновили в обработчике, а не всех подписчиков контекста.
  • api и eventBus сохраняют identity при патче темы и заменяются только при полной пересборке, поэтому указывать их в зависимостях хуков (как в примерах раздела События) корректно и ничего не «дёргает».

Если профилировщик показывает шторм ререндеров в вашем модуле, причина — в вашем собственном управлении состоянием ниже обработчика, а не в контексте.

Клиент api

ctx.api — это HTTP-клиент, который уже несёт аутентификацию пользователя и ограничен областью активного арендатора. Вы никогда не видите токен.

ts
const spaces = await ctx.api.get<Space[]>(`/api/v1/buildings/${building.id}/spaces`);
await ctx.api.post(`/api/v1/buildings/${building.id}/work-orders`, dto);

Доступны get / post / put / patch / delete, каждый принимает необязательный { headers, query, signal }.

Почему это важно: один и тот же компонент работает и в вашей песочнице, и в продакшен-арендаторе клиента, потому что единственное, что между ними меняется — аутентификация и базовый URL — поставляет платформа, а не ваш код.

Чтение данных арендатора

ctx.organization.activeModuleIds показывает, на какие модули лицензирован арендатор. Используйте это для мягкой деградации UI, а не как средство безопасности: лицензирование обеспечивается на сервере через @RequiresLicense(), а проверка на клиенте — удобство, а не граница.

tsx
const { organization } = usePlatformContext();
const hasCafm = organization.activeModuleIds?.includes('@tv/module-cafm');

Не обходите его стороной

Контракт таков: PlatformContext — ваша единственная дверь. Если вы замечаете, что читаете localStorage, собираете URL Keycloak или жёстко прописываете https://tv-api... — остановитесь: этот путь не переживёт переход между арендаторами и находится вне того, что поддерживает платформа.

→ Далее: События

Создано на платформе Tango Vision. Вопросы? developers@tango.vision