Basic state
The useState reference opens with four basic state shapes: a counter, a text field, a checkbox, and a form. First steps covered the counter — here are the other three as streams.
The pattern is always the same: state lives in a Subject (or BehaviorSubject when it has a current value), plain event handlers push into it with .next(...), and components read it with a hook. The split to remember: controlled inputs read useSyncObservable (the caret and IME need synchronous updates), everything else defaults to useObservable.
Text field (string)
Checkbox (boolean)
This one uses a module-scoped BehaviorSubject: it holds a current value and emits it synchronously, so the first render already has the real state — and living outside the component, it survives remounts and can be shared or composed with other streams. Compare with the text field above, where useState(() => new Subject()) keeps the state per component instance.
Form (two variables)
Two independent pieces of state, just like two useState calls — and a preview of the hook split: the name feeds a controlled input (useSyncObservable), while the age only feeds rendering (useObservable).
Where to next
So far streams have only replaced useState. The payoff starts when state involves time — continue to Timers & time ago.