use* vs create*
Most utilities come in two forms:
| Form | Where to use it |
|---|---|
use* | React component or custom hook body |
create* | "use scope", useScope factory, store setup, or another lifecycle-owned factory |
use* Hook Wrappers
Section titled “use* Hook Wrappers”Use use* when you are writing regular React hook code:
import { useObservable } from "@usels/core";import { useDebounced } from "@usels/core";
function Search() { const draft$ = useObservable(""); const query$ = useDebounced(draft$, { ms: 150 });
return <input value={draft$.get()} onChange={(event) => draft$.set(event.currentTarget.value)} />;}The hook wrapper follows React’s hook rules and owns setup through React.
create* Primitives
Section titled “create* Primitives”Use create* inside a scope or store setup:
import { createDebounced, observable } from "@usels/core";
function Search() { "use scope";
const draft$ = observable(""); const query$ = createDebounced(draft$, { ms: 150 });
return <input value={draft$.get()} onChange={(event) => draft$.set(event.currentTarget.value)} />;}The scope owns the lifecycle, so the primitive does not need to be a React hook.
Web Example
Section titled “Web Example”The same rule applies to DOM APIs:
import { createRef$ } from "@usels/core";import { createElementSize } from "@usels/web";
function ResizablePanel() { "use scope";
const el$ = createRef$<HTMLDivElement>(); const { width$, height$ } = createElementSize(el$);
return <div ref={el$}>{width$.get()} x {height$.get()}</div>;}In a regular hook body, use useRef$ and useElementSize instead.
Why create* Fits Scope
Section titled “Why create* Fits Scope”Inside a scope, create* reads naturally because the scope already owns lifecycle. The primitive does not need hook rules — setup happens once per scope, cleanup happens when the scope tears down:
import { createDebounced, observable, observe } from "@usels/core";
function SearchBox({ onSearch }: { onSearch: (query: string) => void }) { "use scope";
const draft$ = observable(""); const query$ = createDebounced(draft$, { ms: 150 });
observe(() => { onSearch(query$.get()); });
return <input value={draft$.get()} onChange={(event) => draft$.set(event.currentTarget.value)} />;}Same component written with use* would need to be inside a component body with hook-rule constraints. Inside scope, create* keeps the factory side-effect-free from React’s perspective.
Rule Of Thumb
Section titled “Rule Of Thumb”If React is the lifecycle boundary, use use*.
If a use-legend scope or store is the lifecycle boundary, use create*.
createStore() is a store definition API, so it is the exception you define at
module scope.
Related
Section titled “Related”- Scope & Lifecycle — the lifecycle model that makes
create*safe without hook rules. - Effects API — the scope-level effect primitives paired with
create*. - TypeScript — how
create*anduse*types relate in team-scale code.