Skip to content

Небольшое погружение в исходники ​

ts
import { useSyncExternalStore, useDebugValue, useMemo, useState } from 'react'
import { ISignalLike } from '../../core/types'

/**
 * ⚛️ УЛЬТИМАТИВНЫЙ ХУК ДЛЯ СТЯГИВАНИЯ ДАННЫХ ИЗ ГРАФА В СРЕДУ REACT
 * Автоматически выводит тип внутренней структуры данных (V) из любого сигнала или вычисляемого свойства.
 */
export function useReactiveValue<V>(signal: ISignalLike<V>): V;
export function useReactiveValue<T extends object>(proxy: T): T;
export function useReactiveValue<T>(primitive: T): T;
export function useReactiveValue(signal: any): any {
  const isProxy = signal && typeof signal === 'object' && '__subscribe' in signal
  const isSignal = signal && typeof signal === 'object' && 'subscribe' in signal

  if (!isSignal && !isProxy) {
    return signal
  }

  const rawNode = signal._node || signal
  const engine = rawNode.engine || signal.engine

  // Локальный тикет рендеринга для useSyncExternalStore.
  const [ticket, setTicket] = useState(0)

  // 🟢 КАНОНИЧЕСКИЙ ВЕРСИОННЫЙ СНАПШOТ useSyncExternalStore С СИНХРOННЫМ ПOДТЯГИВАНИЕМ КЭША
  useSyncExternalStore(
    useMemo(() => (onStoreChange: () => void) => {
      const triggerStoreRerender = () => {
        setTicket((t) => t + 1)
        onStoreChange()
      }

      if (rawNode.type === 'computed' && typeof signal.__subscribe === 'function') {
        return signal.__subscribe(triggerStoreRerender)
      }

      if (rawNode.type !== 'computed' && '__subscribe' in signal && typeof signal.__subscribe === 'function') {
        return signal.__subscribe(triggerStoreRerender)
      }

      return signal.subscribe(triggerStoreRerender)
    }, [signal, rawNode]),

    () => ticket,
    () => 0
  )

  useDebugValue(ticket)

  // ⚛️ ТОПОЛОГИЧЕСКИЙ Pull: Стягиваем свежее значение в теле рендера под untrack
  if (engine && 'untrack' in engine) {
    return engine.untrack(() => (signal.value !== undefined ? signal.value : signal))
  }

  return signal.value !== undefined ? signal.value : signal
}