@gravity-ui/graph
Version:
Modern graph editor component
68 lines (67 loc) • 2.11 kB
JavaScript
import { useCallback, useEffect, useLayoutEffect, useMemo, useSyncExternalStore } from "react";
import { computed, effect } from "@preact/signals-core";
import { useFn } from "../utils/hooks/useFn";
/**
* Hook to subscribe to a signal and get the current value.
* @param signal - Signal to subscribe to
* @returns Current value of the signal
*
* @example
* ```tsx
* const geometry = useSignal(block.$geometry);
* ```
*/
export function useSignal(signal) {
const subscribe = useCallback((onChangeFn) => {
return signal.subscribe(onChangeFn);
}, [signal]);
const getSnapshot = useCallback(() => {
return signal.value;
}, [signal]);
return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
}
/**
* Hook to subscribe to a computed signal and get the current value.
* @param compute - Computed function to subscribe to
* @param deps - Dependencies to subscribe to
* @returns Current value of the computed signal
*
* @example
* ```tsx
* const geometry = useComputedSignal(() => block.$geometry.value, [block]);
* ```
*/
export function useComputedSignal(compute, deps) {
const handle = useFn(compute);
const signal = useMemo(() => computed(() => handle()), deps);
return useSignal(signal);
}
/**
* Hook to subscribe to a signal and get the current value.
* @param effectFn - Effect function to subscribe to
* @param deps - Dependencies recreate the effect when they change
* @returns Current value of the signal
*
* @example
* ```tsx
* useSignalEffect(() => {
* console.log(block.$geometry.value);
* }, [block]);
* ```
*/
export function useSignalEffect(effectFn, deps) {
const handle = useFn(effectFn);
useEffect(() => {
return effect(() => handle());
}, deps);
}
/**
* Like {@link useSignalEffect}, but runs the subscription setup in `useLayoutEffect`
* so the effect fires synchronously after DOM updates and before paint.
*/
export function useSignalLayoutEffect(effectFn, deps) {
const handle = useFn(effectFn);
useLayoutEffect(() => {
return effect(() => handle());
}, deps);
}