Using Signals in React

Squeeds Julkalender | 2023-12-17 | Nicolas Hervy
First, what is Signals? It's a component independent state management system that works off minimal language (signal, computed, effect) to guarantee consistent synchronization of state and view. If Reacts internal state stands for async reactivity, Signals are for synchronous. Signals are also globally accessible via regular ES imports.

In simple terms: Signals are things that hold a value; reactive variables so to speak. Effects are blocks of code (defined with createEffect in Solid) that automatically re-run when any signals accessed inside of them change.

The way that this helps with practical performance, compared to React for example, is that JSX is compiled into effects that update DOM directly in the most efficient way possible, without an abstraction like Vdom (Reacts virtual dom).

Signals has been a pattern since the 60s. It found it's way into Javascript around 2010 in a couple of libraries and recently found its way into the spotlight again through SolidJS, Preact, and lately also Svelte.

In case you missed it in the first paragraph signals consist of:

  • Signal - function that creates the signals variable.
  • Computed - used to create a computed property that automatically updates whenever its dependencies change.
  • Effect - A function that is run every time a signal variable placed inside of it changes.

Example Code

I have created a React project available online in CodeSandbox that runs the code in this article. Please head over and push som buttons. Fork it and continue the tweak it to your hearts content. Here is the link:

How to use it in React

We are going to use Preact signals implementation in a React project.

`npm install @preact/signals-react`

Signals is unlike Redux not ment to contain everything in a big single source of truth. Instead you create a signal for every need you have. But I think you will find keeping all signals initialization in a single "store" file will keep them organized in a manageable way.
So in my example project, I create a store.ts file from where I subsequently can import my signal variables from any where in my app.

Store example using Signals

I am also adding a computed function that takes a Signal and computes a new signal when the first updates. (the test_prime function is here to but not relevant to case in point)

Then I add two components in my React application. In the first I'll add my Signal `count`. Line 21
I also add a button that increments `count`.

Code example

In my second component (I've just included the render function for the sake of brevity) I do everything almost the same except for one small difference. I add "value" as a property on my `count`signal. Line 4.

Code example

So the difference is that without "value" (as in comp1.tsx) it will not trigger a re-render of the full component. Only the signal will update, leaving the React vdom untouched. In my example code, this is visualized by running/not running the console.log as well as the ui effect.


Signals selective re-rendering can of course lead to performance improvements. If React context performs best on the low end of the frequent updates scale (change a theme etc), then Signals sits right on the other end of the scale where it handles frequent updates really well if set up so that it doesn't cause re-renders in the rest of the UI. Ideally it operates just in the small isolated island designated to it securely separated from the rest of the application.

The choice between using signals or React context ultimately depends on the specific requirements and complexity of your application.


In the Preact/React signals case I'd say that complex data objects stored as signals tend to be more difficult to manage in a similarly optimized way. It's sure doable and you can play around with another test I set up in my page2 setup in the Codesandbox project.

Again, my example code is from my experiments with signals in React at: