Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@preact/signals

preactjs1.3mMIT2.0.4TypeScript support: included

Manage state with style in Preact

readme

Signals

Signals is a performant state management library with two primary goals:

  1. Make it as easy as possible to write business logic for small up to complex apps. No matter how complex your logic is, your app updates should stay fast without you needing to think about it. Signals automatically optimize state updates behind the scenes to trigger the fewest updates necessary. They are lazy by default and automatically skip signals that no one listens to.
  2. Integrate into frameworks as if they were native built-in primitives. You don't need any selectors, wrapper functions, or anything else. Signals can be accessed directly and your component will automatically re-render when the signal's value changes.

Read the announcement post to learn more about which problems signals solves and how it came to be.

Installation:

npm install @preact/signals

Preact Integration

The Preact integration can be installed via:

npm install @preact/signals

It allows you to access signals as if they were native to Preact. Whenever you read a signal inside a component we'll automatically subscribe the component to that. When you update the signal we'll know that this component needs to be updated and will do that for you.

// The Preact adapter re-exports the core library
import { signal } from "@preact/signals";

const count = signal(0);

function CounterValue() {
    // Whenever the `count` signal is updated, we'll
    // re-render this component automatically for you
    return <p>Value: {count.value}</p>;
}

Hooks

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.

import { useSignal, useComputed, useSignalEffect } from "@preact/signals";

function Counter() {
    const count = useSignal(0);
    const double = useComputed(() => count.value * 2);

    useSignalEffect(() => {
        console.log(`Value: ${count.value}, value x 2 = ${double.value}`);
    });

    return (
        <button onClick={() => count.value++}>
            Value: {count.value}, value x 2 = {double.value}
        </button>
    );
}

Rendering optimizations

The Preact 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.

import { signal } from "@preact/signals";

const count = signal(0);

// Unoptimized: Will trigger the surrounding
// component to re-render
function Counter() {
    return <p>Value: {count.value}</p>;
}

// Optimized: Will update the text node directly
function Counter() {
    return <p>Value: {count}</p>;
}

To opt into this optimization, simply pass the signal directly instead of accessing the .value property.

Attribute optimization (experimental)

We can also pass signals directly as an attribute to an HTML element node.

import { signal } from "@preact/signals";

const inputValue = signal("foobar");

function Person() {
    return <input value={inputValue} onInput={...} />;
}

This way we'll bypass checking the virtual-dom and update the DOM property directly.

License

MIT, see the LICENSE file.

changelog

@preact/signals

2.0.4

Patch Changes

2.0.3

Patch Changes

2.0.2

Patch Changes

2.0.1

Patch Changes

  • #647 655905b Thanks @jviide! - Ensure that text effects get disposed

  • #630 4b9144f Thanks @JoviDeCroock! - Change the way we deal with state settling hooks, when we know we are dealing with hooks that can settle their A -> B -> A state (and wind up at the same value). We should not verbatim rerender in our custom shouldComponentUpdate. Instead we should trust that hooks have handled their own state settling.

2.0.0

Major Changes

  • #604 fea3e8d Thanks @JoviDeCroock! - Defer all DOM updates by an animation frame, this should make it so that any previously synchronous DOM update will be instead delayed by an animation frame. This allows Preact to first perform its own render cycle and then our direct DOM updates to occur. These will now be performed in a batched way which is more performant as the browser is prepared to handle these during the animation frame.

    This does impact how Preact based signals are tested, when you perform a signal update, you'll need to wrap it in act. In a way this was always the case, as a signal update that resulted in a Preact state update would require it to be wrapped in act, but now this is the norm.

Minor Changes

Patch Changes

  • #609 8e6e2de Thanks @JoviDeCroock! - Change timing to a double microtask so we are behind the Preact render queue but can't delay as much as a user-input coming in.

1.3.0

Minor Changes

  • #578 931404e Thanks @JoviDeCroock! - Allow for passing no argument to the signal and the type to be automatically inferred as T | undefined

Patch Changes

1.2.3

Patch Changes

1.2.2

Patch Changes

  • #415 79efe32 Thanks @prinsss! - Fix error when using useSignal with UMD builds of @preact/signals.

1.2.1

Patch Changes

1.2.0

Minor Changes

  • #387 6e4dab4 Thanks @XantreGodlike! - Removed difference in behaviour between adapters, signals that use a JSX value will correctly re-render the whole component rather than attempting the JSX-Text optimization.

Patch Changes

1.1.5

Patch Changes

1.1.4

Patch Changes

1.1.3

Patch Changes

1.1.2

Patch Changes

1.1.1

Patch Changes

1.1.0

Minor Changes

  • #91 fb74bb9 Thanks @JoviDeCroock! - add the useSignalEffect hook

  • #183 79ff1e7 Thanks @jviide! - Add ability to run custom cleanup logic when an effect is disposed.

    effect(() => {
      console.log("This runs whenever a dependency changes");
      return () => {
        console.log("This runs when the effect is disposed");
      });
    });

Patch Changes

1.0.4

Patch Changes

1.0.3

Patch Changes

  • ab5bd99: Fix swapping and HMR for signals when used as text

1.0.2

Patch Changes

1.0.1

Patch Changes

  • c7c0d91: Add marker for devtools to Text that is created when a signal is passed into JSX

1.0.0

Major Changes

  • 2ee8489: The v1 release for the signals package, we'd to see the uses you all come up with and are eager to see performance improvements in your applications.

Patch Changes

0.0.4

Patch Changes

  • 702a9c5: Update TypeScript types to mark computed signals as readonly
  • 5f8be64: Optimize size of CJS & UMD bundles.
  • Updated dependencies [702a9c5]

0.0.3

Patch Changes

  • 812e7b5: Fix batch() not re-exported from preact adapter
  • 8e9bf67: Fix incorrect TypeScript paths
  • f71ea95: Avoid incrementing Preact adapter when core changes
  • Updated dependencies [4123d60]

0.0.2

Patch Changes

  • 1e4dac5: Add prepublishOnly scripts to ensure we're publishing fresh packages
  • 9ccf359: Align signal rendering in Text positions with VDOM text rendering - skip rendering of null, undefined and boolean values.
  • 1171338: Fix wrong path for TypeScript definitions in package.json
  • Updated dependencies [1e4dac5]