signal
import {useSignal, useSyncSignal, useSignalEffect, useComputed} from '@kaiverse/signal-react'A collection of hooks that allow us to use signal features inside React components.
Includes:
useSignal- create aSignal.useSyncSignal- create aSignal. Integrated withuseSyncExternalStore.useSignalEffect- register aSignaleffect.useComputed- create a computed value fromSignal(s).
Installation
No need to install the core package @kaiverse/signal separately.
pnpm add @kaiverse/signal-reactnpm i @kaiverse/signal-reactyarn add @kaiverse/signal-reactuseSignal
Create a Signal inside React component.
useSignal uses useReducer and returns a snapshot of Signal. It works better with concurrent rendering but has temporary tearing issue.
Consider using useSyncSignal which uses useSyncExternalStore that solves tearing issues, but doesn’t work well with concurrent rendering. It’s a trade-off, choose wisely.
Read more about the tearing issue.
useSyncSignal
Create a Signal inside React component.
useSyncSignal is integrated with useSyncExternalStore (uSES) which is a recommended way to use “external stores” in React.
useSyncSignal works well in most cases. However, uSES doesn’t work with concurrent rendering. useSyncSignal’s setter wrapped with startTransition won’t behave as expected.
Suspend a render based on a store value returned by uSES will trigger the nearest Suspense fallback instead of showing the old UI.
Read more: useSyncExternalStore
useSignal, on the other hand, doesn’t use uSES. It returns a snapshot of Signal and uses useReducer to perform a re-render on Signal changes.
As a result, It works better with concurrent rendering but suffers from temporary tearing issue.
It’s a trade-off after all. Choose the one that fits your use case.
useSignalEffect
Signal effect inside React component. It accepts a imperative function that will run whenever dependencies change. Dependencies are Signals that are used inside the Effect itself.
useSignalEffect can track either global Signal(s) or local (both inside or outside component) Signal(s) or all of them together.
import {createSignal, useSignalEffect} from '@kaiverse/signal-react'
const [count, setCount] = createSignal(0)
export function UseSignalEffectExample() { useSignalEffect(() => { console.log('count =', count()) // this will run whenever the increment button is clicked })
return ( <button type="button" onClick={() => setCount(count() + 1)}> Increment </button> )}useComputed
Derived signals inside React component.
Usually used to create a computed Signal from Signal(s) or to bind Signal(s), that created outside components, to React reactive system.
import {useSignal, useComputed} from '@kaiverse/signal-react'import {globalCountSignal} from './global-store'
const [globalCount, setGlobalCount] = globalCountSignal
export function UseComputedExample() { const [count, setCount] = useSignal(0) const sum = useComputed(() => count() + globalCount())
return ( <> <button type="button" onClick={() => setCount((c) => c + 1)}> count++ </button> <button type="button" onClick={() => setGlobalCount(globalCount() + 2)}> Increase global count </button> Result: {count()} + {globalCount()} = {sum()} </> )}import {createSignal} from '@kaiverse/signal-react'export const globalCountSignal = createSignal(0)