Skip to content

useAtom.ts ​

Назначение файла ​

Модуль предоставляет React-хук useAtom(), который подписывает компонент на одно реактивное значение Atom<T>.

Общая информация ​

useAtom() решает базовую задачу чтения Nrgy-атома из React. Хук построен на useSyncExternalStore() из React: сам атом выступает функцией получения снимка, а синхронный эффект уведомляет React об изменениях.

Поскольку значение читается из атома в каждом рендере, смена самого атома source видна в том же коммите. Обновления атома доставляются синхронно: обновление внутри обработчика события или внутри act() рендерится без ожидания микрозадачи, а несколько обновлений в одном обработчике или внутри batch() дают один рендер.

Хук требует React 18 или новее.

Концептуальная архитектура ​

Хук состоит из двух частей:

  1. subscribe мемоизируется через useCallback() для каждого source. Он создает подписку через syncEffect(source, onStoreChange) и возвращает subscription.destroy как функцию отписки.
  2. source передается в useSyncExternalStore() и как getSnapshot, и как getServerSnapshot. Атомы сохраняют ссылочную стабильность значения между изменениями, поэтому React может сравнивать снимки через Object.is.

Следствия такой конструкции:

  • Атом source должен быть стабильным между рендерами. Атом, созданный в теле рендера без мемоизации, приводит к новой подписке на каждый рендер.
  • Ошибка, брошенная атомом, проявляется как ошибка рендера и может быть обработана error boundary.
  • Установка атома в теле рендера вызывает предупреждение React об обновлении компонента во время рендера.

Описание публичного API ​

useAtom<T>(source: Atom<T>): T ​

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

Примеры использования ​

tsx
import React from 'react';
import { atom } from '@nrgyjs/core';
import { useAtom } from '@nrgyjs/react';

const counter = atom(0);

export function CounterValue() {
  const value = useAtom(counter);

  return <span>{value}</span>;
}