1. Introduction
A few weeks ago, I was deep into optimizing a React dashboard for one of my freelance clients. The project looked clean on the surface — reusable components, proper state management with hooks, and even some memoization to avoid unnecessary re-renders.
But something felt off.
As I added new widgets to the dashboard — live stats, graphs, real-time notifications — the UI started lagging. Even minor state changes triggered re-renders in places I didn’t expect. Debugging became a game of tracing useEffect
, checking dependency arrays, and managing stale closures. Every performance improvement felt like a patch on a larger architectural inefficiency.
The main pain point?
- State was distributed across deeply nested components.
-
useState
was everywhere. -
useEffect
chains were hard to track. - Memoization (
React.memo
,useCallback
) felt like fighting React itself.
That’s when I came across an article that mentioned something called Signals. I had heard the term before in Solid.js, but never gave it serious thought. But this time, I decided to dig deeper.
And honestly, it changed how I think about reactivity in UI development.
2. What Are Signals?
Let’s start simple.
The Layman Explanation
Imagine you have a value — say, a counter. Now imagine any place that uses this counter automatically updates when the value changes, without you writing any special logic for re-rendering or managing dependencies.
That’s a Signal.
You don’t need useState
, useEffect
, or even memo
. Signals just work — they’re reactive by nature. When a signal’s value changes, everything subscribed to it reacts automatically and precisely.
The Technical Definition
A Signal is a reactive primitive — a small unit of state — that notifies dependents when it changes. It doesn’t trigger component-level re-renders like React state does. Instead, it updates only the part of the DOM that depends on it.
This fine-grained reactivity is what makes Signals so powerful.
Code Comparison: React vs Signals
Let me show you a simple example — a counter.
React Version:
// Counter.jsx
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
</div>
);
}
Now with Signals (using Preact Signals):
// Counter.jsx
import { signal } from "@preact/signals-react";
const count = signal(0);
export default function Counter() {
return (
<div>
<p>Count: {count.value}</p>
<button onClick={() => count.value++}>Increment</button>
</div>
);
}
What's Different:
- No hooks.
- No state per component — the signal exists outside and still works.
- Only the exact DOM node (
<p>
) updates when the signal changes.
How It Feels Different
Using signals felt… surprisingly natural.
- The code is cleaner — no boilerplate hooks.
- It’s predictable — changes propagate where they’re used.
- It avoids unnecessary re-renders — which, in large apps, becomes critical.
Of course, it’s not about replacing React. But it opens the door to thinking differently about state.
3. Signals vs React State: A Developer's Viewpoint
Now let’s talk experience — the good, the not-so-good, and the trade-offs.
What I Loved About Signals
- No unnecessary re-renders. Since signals update only where they're used, the rest of the component tree stays untouched.
- Freedom from hook rules. You’re not restricted by the "rules of hooks" (no conditionals, top-level only, etc.).
-
Composable logic. Signals can be derived, composed, or reused without
useEffect
.
For instance:
const price = signal(100);
const quantity = signal(2);
const total = computed(() => price.value * quantity.value);
No useMemo
, no tracking dependencies. It just works.
What React Still Does Better
As much as I appreciated the elegance of Signals, I wouldn’t rush to replace React’s state system entirely.
- Ecosystem support. React has years of tools, libraries, and community patterns.
- DevTools integration. Debugging with React is well-supported. Signals still lack that full ecosystem visibility.
- Predictability in teams. React’s state model — though verbose — is familiar to most developers. Signals introduce a different mindset.
What I Struggled With
- Mindset shift. I had to unlearn the habit of thinking in components + hooks and start thinking in terms of reactive values and computations.
- TypeScript support. Early versions didn’t always provide perfect autocompletion or type inference. This has improved over time, but it’s something to watch.
- Team-wide adoption. If you're working in a team, especially one that's deep into React, introducing signals might create friction or confusion.
Top comments (7)
You do realize that preact "signals" just uses a useEffect and a useState hook under the hood right? You can't trigger a react component to rerender without changing its props, or using those hooks. There are no signals in React.
You're absolutely right — React doesn't support signals natively, and Preact's Signals for React are indeed built on top of React’s useState and useEffect under the hood.
But I think the key value here isn’t that Signals replace React’s internals — it’s that they abstract the boilerplate, simplify reactivity, and allow finer-grained updates through controlled subscriptions.
In my use case (real-time widgets), it helped me avoid scattered effects and made reactive flows easier to manage — even if the mechanics ultimately rely on React primitives.
That said, I fully agree — this isn’t “true signals” like in Solid.js or Qwik. But it’s a helpful step toward thinking reactively beyond hooks.
Appreciate the perspective — would love to hear if you've tried Solid or Preact directly?
I've tried SolidJS and would love to use it more, but alas there's not many companies using it yet.
If it helps you make the code cleaner that's good, I just don't like how they're advertising it as "signals". Should have named it
useSubscribeState
or something like that.Yeah, totally agree — Solid’s approach to signals is the real deal. Preact’s version feels more like a dev experience layer on top of React’s internals.
It helped me write cleaner logic, but I get your point on the naming — maybe something like useReactiveState would’ve set clearer expectations.
Appreciate the thoughts!
the pain of endless useEffect and memo loops is way too real, man, signals honestly sound like a breath of fresh air for this stuff
wondering if you’d actually switch on a real production client project or just stick to what’s familiar
I feel this so much - managing deep React state and hooks gets pretty overwhelming fast. Have you tried scaling signals in a full-blown app yet, or just in smaller widgets?
Some comments may only be visible to logged-in visitors. Sign in to view all comments.