Gathering detailed insights and metrics for @preact/signals-react
Gathering detailed insights and metrics for @preact/signals-react
Gathering detailed insights and metrics for @preact/signals-react
Gathering detailed insights and metrics for @preact/signals-react
@preact/signals-react-transform
Manage state with style in React
@preact-signals/safe-react
Manage state with style in React
@quilted/react-signals
Utilities for working with Preact signals.
@preact-signals/query
A reactive utility for React/Preact that simplifies the handling of data fetching and state management. Powered by Preact Signals, it provides hooks and functions to create reactive resources and manage their state seamlessly.
Manage state with style in every framework
npm install @preact/signals-react
Typescript
Module System
Node Version
NPM Version
@preact/signals-core@1.12.1
Updated on Aug 23, 2025
@preact/signals-preact-transform@0.1.0
Updated on Aug 20, 2025
@preact/signals@2.3.1
Updated on Aug 20, 2025
@preact/signals-debug@1.0.0
Updated on Aug 20, 2025
@preact/signals@2.2.1
Updated on Jun 29, 2025
@preact/signals-react@3.2.1
Updated on Jun 29, 2025
TypeScript (90.09%)
JavaScript (7.14%)
CSS (2.14%)
HTML (0.58%)
Dockerfile (0.04%)
Shell (0.02%)
Total Downloads
7,811,556
Last Day
5,269
Last Week
132,288
Last Month
546,626
Last Year
5,400,997
MIT License
4,209 Stars
882 Commits
116 Forks
26 Watchers
34 Branches
60 Contributors
Updated on Sep 02, 2025
Latest Version
3.3.0
Package Id
@preact/signals-react@3.3.0
Unpacked Size
149.35 kB
Size
30.11 kB
File Count
36
NPM Version
10.8.2
Node Version
18.20.8
Published on
Aug 19, 2025
Cumulative downloads
Total Downloads
Last Day
-2%
5,269
Compared to previous day
Last Week
1.5%
132,288
Compared to previous week
Last Month
4.3%
546,626
Compared to previous month
Last Year
142.1%
5,400,997
Compared to previous year
2
1
Signals is a performant state management library with two primary goals:
Read the announcement post to learn more about which problems signals solves and how it came to be.
The React integration can be installed via:
1npm install @preact/signals-react
We have a couple of options for integrating Signals into React. The recommended approach is to use the Babel transform to automatically make your components that use signals reactive.
Install the Babel transform package (npm i --save-dev @preact/signals-react-transform
) and add the following to your Babel config:
1{ 2 "plugins": [["module:@preact/signals-react-transform"]] 3}
This will automatically transform your components to be reactive. You can then use signals directly inside your components.
1import { signal } from "@preact/signals-react"; 2 3const count = signal(0); 4 5function CounterValue() { 6 // Whenever the `count` signal is updated, we'll 7 // re-render this component automatically for you 8 return <p>Value: {count.value}</p>; 9}
See the Readme for the Babel plugin for more details about how the transform works and configuring it.
useSignals
hookIf you can't use the Babel transform, you can directly call the useSignals
hook to make your components reactive.
1import { useSignals } from "@preact/signals-react/runtime"; 2 3const count = signal(0); 4 5function CounterValue() { 6 useSignals(); 7 return <p>Value: {count.value}</p>; 8}
If you need to instantiate new signals or create new side effects on signal changes inside your components, you can use the useSignal
, useComputed
and useSignalEffect
hooks.
1import { useSignal, useComputed, useSignalEffect } from "@preact/signals-react"; 2 3function Counter() { 4 const count = useSignal(0); 5 const double = useComputed(() => count.value * 2); 6 7 useSignalEffect(() => { 8 console.log(`Value: ${count.value}, value x 2 = ${double.value}`); 9 }); 10 11 return ( 12 <button onClick={() => count.value++}> 13 Value: {count.value}, value x 2 = {double.value} 14 </button> 15 ); 16}
Components rendered using SSR APIs (e.g. renderToString
) in a server environment (i.e. an environment without a global window
object) will not track signals used during render. Components generally don't rerender when using SSR APIs so tracking signal usage is useless since changing these signals can't trigger a rerender.
The React adapter ships with several optimizations it can apply out of the box to skip virtual-dom rendering entirely. If you pass a signal directly into JSX, it will bind directly to the DOM Text
node that is created and update that whenever the signal changes.
1import { signal } from "@preact/signals-react"; 2 3const count = signal(0); 4 5// Unoptimized: Will trigger the surrounding 6// component to re-render 7function Counter() { 8 return <p>Value: {count.value}</p>; 9} 10 11// Optimized: Will update the text node directly 12function Counter() { 13 return ( 14 <p> 15 <>Value: {count}</> 16 </p> 17 ); 18}
To opt into this optimization, simply pass the signal directly instead of accessing the .value
property.
Note The content is wrapped in a React Fragment due to React 18's newer, more strict children types.
The @preact/signals-react/utils
package provides additional utility components and hooks to make working with signals even easier.
The Show
component provides a declarative way to conditionally render content based on a signal's value.
1import { Show } from "@preact/signals-react/utils"; 2import { signal } from "@preact/signals-react"; 3 4const isVisible = signal(false); 5 6function App() { 7 return ( 8 <Show when={isVisible} fallback={<p>Nothing to see here</p>}> 9 <p>Now you see me!</p> 10 </Show> 11 ); 12} 13 14// You can also use a function to access the value 15function App() { 16 return <Show when={isVisible}>{value => <p>The value is {value}</p>}</Show>; 17}
The For
component helps you render lists from signal arrays with automatic caching of rendered items.
1import { For } from "@preact/signals-react/utils"; 2import { signal } from "@preact/signals-react"; 3 4const items = signal(["A", "B", "C"]); 5 6function App() { 7 return ( 8 <For each={items} fallback={<p>No items</p>}> 9 {(item, index) => <div key={index}>Item: {item}</div>} 10 </For> 11 ); 12}
The useLiveSignal
hook allows you to create a local signal that stays synchronized with an external signal.
1import { useLiveSignal } from "@preact/signals-react/utils"; 2import { signal } from "@preact/signals-react"; 3 4const external = signal(0); 5 6function Component() { 7 const local = useLiveSignal(external); 8 // local will automatically update when external changes 9}
The useSignalRef
hook creates a signal that behaves like a React ref with a .current
property.
1import { useSignalRef } from "@preact/signals-react/utils"; 2 3function Component() { 4 const ref = useSignalRef(null); 5 return <div ref={ref}>The ref's value is {ref.current}</div>; 6}
This version of React integration does not support passing signals as DOM attributes. Support for this may be added at a later date.
Using signals in render props is not recommended. In this situation, the component that reads the signal is the component that calls the render prop, which may or may not be hooked up to track signals. For example:
1const count = signal(0); 2 3function ShowCount({ getCount }) { 4 return <div>{getCount()}</div>; 5} 6 7function App() { 8 return <ShowCount getCount={() => count.value} />; 9}
Here, the ShowCount
component is the one that accesses count.value
at runtime since it invokes getCount
, so it needs to be hooked up to track signals. However, since it doesn't statically access the signal, the Babel transform won't transform it by default. One fix is to set mode: all
in the Babel plugin's config, which will transform all components. Another workaround is put the return of the render prop into it's own component and then return that from your render prop. In the following example, the Count
component statically accesses the signal, so it will be transformed by default.
1const count = signal(0); 2 3function ShowCount({ getCount }) { 4 return <div>{getCount()}</div>; 5} 6 7const Count = () => <>{count.value}</>; 8 9function App() { 10 return <ShowCount getCount={() => <Count />} />; 11}
Similar issues exist with using object getters & setters. Since the it isn't easily statically analyzable that a getter or setter is backed by a signal, the Babel plugin may miss some components that use signals in this way. Similarly, setting Babel's plugin to mode: all
will fix this issue.
MIT
, see the LICENSE file.
No vulnerabilities found.