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 aSignal
effect.useComputed
- create a computed value fromSignal
(s).
Installation
No need to install the core package @kaiverse/signal
separately.
pnpm add @kaiverse/signal-react
npm i @kaiverse/signal-react
yarn add @kaiverse/signal-react
useSignal
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)