Skip to content

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 a Signal.
  • useSyncSignal - create a Signal. Integrated with useSyncExternalStore.
  • useSignalEffect - register a Signal effect.
  • useComputed - create a computed value from Signal(s).

Installation

No need to install the core package @kaiverse/signal separately.

Terminal window
pnpm 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.

use-signal-effect-example.tsx
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()}
</>
)
}