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
97.4
Supply Chain
98.2
Quality
94.3
Maintenance
100
Vulnerability
100
License
@preact/signals@2.2.1
Updated on Jun 29, 2025
@preact/signals-react@3.2.1
Updated on Jun 29, 2025
@preact/signals-core@1.11.0
Updated on Jun 29, 2025
@preact/signals-core@1.10.0
Updated on Jun 11, 2025
@preact/signals-react-transform@0.5.2
Updated on Jun 04, 2025
@preact/signals-core@1.9.0
Updated on May 29, 2025
TypeScript (95.26%)
JavaScript (4.66%)
Dockerfile (0.05%)
Shell (0.02%)
Total Downloads
6,911,630
Last Day
3,794
Last Week
103,015
Last Month
474,653
Last Year
5,086,181
MIT License
4,118 Stars
861 Commits
111 Forks
25 Watchers
35 Branches
59 Contributors
Updated on Jul 03, 2025
Minified
Minified + Gzipped
Latest Version
3.2.1
Package Id
@preact/signals-react@3.2.1
Unpacked Size
148.53 kB
Size
30.00 kB
File Count
36
NPM Version
10.8.2
Node Version
18.20.8
Published on
Jun 29, 2025
Cumulative downloads
Total Downloads
Last Day
-0.6%
3,794
Compared to previous day
Last Week
-10.3%
103,015
Compared to previous week
Last Month
-8.5%
474,653
Compared to previous month
Last Year
194.9%
5,086,181
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.
No security vulnerabilities found.