Условный рендеринг
Простыми словами
Как показать или спрятать кусок страницы по условию — и почему это компоненты (Show, Dynamic), а не просто тернарник.
Значения в JSX — привязки: они патчат текст и атрибуты на месте. Когда должна измениться структура DOM, объявляется динамический регион.
<Show>
import { Show } from "@continuum-js/dom";
<Show when={user} fallback={() => <Login />}>
{(u) => <Profile user={u} />}
</Show>;when принимает State<T | null | undefined | false>. Поддерево перестраивается только при смене истинности — обновления уже-истинного значения ничего не перестраивают (ребёнок получает значение на момент переключения; для живых частей передавайте внутрь States).
Функциональная форма для кода без JSX — when(cond, then, else?) с State<boolean>.
<Dynamic> — переключение по значению
Когда веток больше двух, регион ключуется самим значением:
import { Dynamic } from "@continuum-js/dom";
<Dynamic value={state}>
{(s) =>
s.status === "loading" ? (
<Spinner />
) : s.status === "error" ? (
<ErrorBox error={s.error} />
) : s.status === "ok" ? (
<Profile user={s.value} />
) : null
}
</Dynamic>;Регион перестраивается при изменении value (Object.is). Чтобы не перестраивать по несущественным изменениям, сузьте State и уберите дубликаты:
import { dedupe } from "@continuum-js/std";
const status = dedupe(state.map((s) => s.status));dyn — примитив
Show и Dynamic — сахар над dyn(state, render): регионом между комментариями-маркерами, который при смене значения уничтожает старое поддерево и строит новое. Берите dyn напрямую, когда пишете собственный control-flow-компонент — Outlet роутера устроен ровно так, с ключом по идентичности роута.
<Portal>
Структура, которая рендерится в другом месте (модалки, тултипы), но принадлежит времени жизни компонента:
<Portal mount={document.body}>
<div class="modal">…</div>
</Portal>Содержимое удаляется и уничтожается вместе с владеющим поддеревом, где бы оно ни было смонтировано.
<Catch> — граница ошибок
Исключение при построении куска страницы не должно убивать всё приложение. <Catch> показывает вместо упавшего поддерева fallback и даёт повторить:
import { Catch } from "@continuum-js/dom";
<Catch
fallback={(error, reset) => (
<div class="error">
Что-то сломалось: {String(error)}
<button onClick={reset}>Попробовать снова</button>
</div>
)}
>
{() => <RiskyWidget />}
</Catch>;- Дети — обязательно thunk (
{() => …}): жадный JSX выполнился бы (и упал) до того, какCatchполучит управление. - Ловится: исключение при построении детей и исключение при пересборке любого вложенного
Show/Dynamic/dynвнутри границы. Владение упавшего поддерева уничтожается — никаких утёкших подписок и таймеров. resetстроит детей заново с нуля; исключение в самом fallback'е эскалирует к внешней границе.- Не ловится: исключения внутри
map-функций привязок (держите их чистыми). Ошибки асинхронщины вообще не летят исключениями —performиresourceотдают их данными (Result,Async), которые рендерятся как любые значения.
Незнакомый термин? Вся терминология этой документации объяснена в глоссарии.