What Are Signals? A Deep Dive into Fine‑Grained Reactive State Management
This article explains the concept of Signals as a fast, fine‑grained reactive state primitive, compares its usage and performance with hooks, SolidJS, and Vue, and provides hands‑on implementations and integration tips for modern frontend frameworks.
What are Signals?
We start with an article by Preact author Jason Miller.
Preact introduced Signals, providing fast reactive state primitives (or atoms). Signals have the following characteristics:
They feel like using raw data structures.
They automatically update when values change.
They update the DOM directly (i.e., no VDOM).
They have no dependency array.
Below is a basic usage example of Signals:
import { signal } from "@preact/signals";
const count = signal(0);
function Counter() {
const value = count.value;
const increment = () => {
count.value++;
};
return (
<div>
<p>Count: {value}</p>
<button onClick={increment}>click me</button>
</div>
);
}The API is very similar to SolidJS's createSignal, and the .value accessor resembles Vue's Ref. Signals maintain performance even as applications grow, offering fine‑grained state management without memorization tricks. They bypass passing data through the component tree and update referenced components directly, reducing mental overhead and ensuring optimal performance.
Below is a performance comparison between hook‑based state (as atoms) and Signals:
Signals achieve this performance thanks to:
Lazy evaluation – only used values are tracked and updated.
Optimal update strategy.
Optimal dependency tracking – no need to specify dependencies.
Direct state access without selectors or extra hooks.
Signals can exist outside components, unlike hook‑based state.
Can Signals serve both Preact and other frameworks? The goals of Signals show that they can be framework‑agnostic.
Currently, Signals can be used standalone, without depending on a UI framework. Example sandbox: https://codesandbox.io/s/tender-burnell-7c7g9n?file=/src/index.js
Other Frameworks
Switching to SolidJS, here is a reactive data example:
import { createSignal, onCleanup } from "solid-js";
import { render } from "solid-js/web";
const App = () => {
const [count, setCount] = createSignal(0);
const timer = setInterval(() => setCount(count() + 1), 1000);
onCleanup(() => clearInterval(timer));
return <div>{count()}</div>;
};
render(() => <App />, document.getElementById("app"));SolidJS also uses Signals as the foundation; createSignal can be used inside or outside components, similar to Preact. It can serve as local state or global state. The similarities include:
Fine‑grained reactive updates.
No need to define dependencies.
Lazy value retrieval.
SolidJS's reactivity is comparable to Mobx and Vue, but it updates the DOM directly without a VDOM, resulting in strong performance.
Three Elements of Reactive State Management
Signal
A Signal is a reactive data unit; similar concepts are called Observables, Atoms, or Refs in other libraries.
const [count, setCount] = createSignal(0);
console.log(count()); // 0
setCount(5);
console.log(count()); // 5Some APIs use .value instead of a function call, which can be implemented with getters, setters, or proxies.
Reactions
Reactions (often called Effects) run side‑effects when data changes.
const [count, setCount] = createSignal(0);
createEffect(() => console.log("The count is", count()));
setCount(5);Derivations
Derivations (e.g., computed, memo) derive new values from signals and cache results.
const [firstName, setFirstName] = createSignal("John");
const [lastName, setLastName] = createSignal("Smith");
const fullName = createMemo(() => `${firstName()} ${lastName()}`);
console.log(fullName);Reactive Characteristics
Reactive data management stores links between nodes; when a node updates, the system checks and updates linked nodes, removing stale dependencies.
Example demonstrating fine‑grained updates:
const [firstName, setFirstName] = createSignal("a");
const [lastName, setLastName] = createSignal("b");
const [showFullName, setShowFullName] = createSignal(true);
const displayName = createMemo(() => {
if (!showFullName()) return firstName();
return `${firstName()} ${lastName()}`;
});
createEffect(() => console.log("Name:", displayName()));
// a b
setShowFullName(false); // a
setLastName("c"); // no change
setShowFullName(true); // a cRunning the example: https://codesandbox.io/s/tender-burnell-7c7g9n?file=/src/index.js
Manual Implementation
Reactive state management relies on the observer pattern: when a Signal updates, Reactions subscribed to it are triggered.
Signals
Basic implementation of a signal:
const createSignal = (value) => {
const setter = (newValue) => value = newValue;
return [() => value, setter];
};
const [name, setName] = createSignal('a');
console.log(name());
setName('b');
console.log(name());Reactions
Implementation of a reaction (effect) with subscription handling:
const context = [];
const createEffect = (fn) => {
const execute = () => {
running.deps.clear();
context.push(running);
try { fn(); } finally { context.pop(running); }
};
const running = { execute, deps: new Set() };
execute();
};Derivations
Derivation (memo) implementation:
const createMemo = (fn) => {
const [memo, setMemo] = createSignal();
createEffect(() => setMemo(fn()));
return memo;
};Full demo: https://codesandbox.io/s/elastic-blackwell-br79m2?file=/src/index.js
Back to React
React offers many state‑management options; see the referenced article for a comparison.
Valtio aligns closely with Signals in React, providing:
No dependency array.
External store without component coupling.
However, React still relies on VDOM updates, unlike SolidJS's direct DOM updates. Future React improvements such as React Forget or useEvent may address this.
Conclusion
This article does not aim to guide state‑management selection or compare pros and cons; it simply introduces concepts and methods of reactive state management for reference.
References
https://preactjs.com/blog/introducing-signals
https://preactjs.com/guide/v10/signals/
https://dev.to/ryansolid/a-hands-on-introduction-to-fine-grained-reactivity-3ndf
https://indepth.dev/posts/1289/solidjs-reactivity-to-rendering
https://cn.vuejs.org/guide/extras/reactivity-in-depth.html
https://my5353.com/gCocL
https://mp.weixin.qq.com/s/26_yYH5fbDyMTEKOMcNxtA
Alipay Experience Technology
Exploring ultimate user experience and best engineering practices
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
