Standalone Components and Signals
This whole course has quietly used the modern direction already — every component has been standalone: true, and Chapters 10–11 used provideRouter/provideHttpClient rather than the older module setup. This chapter names those choices explicitly, then introduces signals — Angular's newer reactivity primitive, the closest thing in Angular to React's useState.
Standalone Components, Recapped
Historically, Angular grouped components into NgModules — separate files declaring which components, directives, and pipes belonged together and what they could use. Standalone components (now the default) drop that layer: each component declares its own imports directly, as seen in every example so far. The result is less boilerplate, no app.module.ts to maintain, and an import list that lives right next to the component using it.
@NgModule with a declarations array and a root AppModule. It's fully supported and not going away soon, but new projects should use standalone (the ng new default). Recognize the module-based structure when reading older code; this course deliberately teaches only the standalone approach.
Signals — A Reactive Value
signal(0) creates a reactive value holding 0. Reading it is a function call — count(), both in the template and in code. Writing is done with .set(value) (a new value) or .update(fn) (based on the current one) — directly parallel to React's setCount(5) and setCount(n => n + 1). When a signal changes, Angular knows precisely which parts of the template depend on it and updates only those, more surgically than the older change-detection mechanism.
| Signal | React useState equivalent |
|---|---|
| count = signal(0) | const [count, setCount] = useState(0) |
| count() | count (read) |
| count.set(5) | setCount(5) |
| count.update(n => n + 1) | setCount(n => n + 1) |
computed — Derived Signals
computed derives a new signal from others — its value automatically recalculates whenever any signal it reads changes, and (importantly) is cached until then, so it only recomputes when genuinely needed. This is the signals version of React's useMemo (Intermediate Chapter 7), but the dependency tracking is automatic: there's no dependency array to maintain — Angular knows total depends on price and quantity simply because it read them.
effect — Reacting to Signal Changes
effect runs a side effect whenever any signal it reads changes — automatically tracked, the same way computed works. It's the rough equivalent of React's useEffect with the relevant value in its dependency array, again with no manual dependency list. Effects are for genuine side effects (logging, syncing to localStorage); deriving a value should use computed instead.
Why Signals Matter
Signals are Angular's strategic direction for reactivity — gradually offering a simpler, more explicit, and more performant alternative to the change-detection-plus-RxJS model that came before. They don't replace RxJS (Observables are still the right tool for streams of events and HTTP, Chapter 11), but for component-local state, signals are increasingly the recommended default. Inputs can even be signals now (input() instead of @Input()), and the async pipe has a signal counterpart in toSignal() — the ecosystem is steadily building around them.
signal/set/update is useState, computed is useMemo, effect is useEffect — all with automatic dependency tracking instead of manual arrays. If the rest of Angular felt like a different paradigm, this is the chapter where it converges back toward familiar ground.
| Angular signals | React hooks |
|---|---|
| signal() | useState |
| computed() | useMemo (auto-tracked) |
| effect() | useEffect (auto-tracked) |
Coding Challenges
Build a counter using a signal, with +1/-1/reset buttons calling set/update, reading the value with count() in the template.
📄 View solutionBuild a component with price and quantity signals and a computed total signal, plus inputs/buttons to change price and quantity, confirming total updates automatically with no manual recalculation.
📄 View solutionBuild a component with a signal whose value is persisted to localStorage via an effect (saving on every change) and read back as the initial value, so it survives a page refresh — the signals version of the React useLocalStorage hook.
📄 View solutionChapter 13 Quick Reference
- Standalone components (the default) replace NgModules; each declares its own
imports - signal(value) — a reactive value; read with
x(), write with.set()/.update()(=useState) - computed(() => ...) — a derived signal, auto-recalculated and cached (=
useMemo, no dep array) - effect(() => ...) — runs a side effect when read signals change (=
useEffect, auto-tracked) - Signals are Angular's strategic direction for reactivity — preferred for component-local state
- Signals complement, don't replace, RxJS — Observables still own event streams and HTTP
- Next chapter: testing — Jasmine, Karma, and TestBed (the final chapter)