API reference · generated from source
Read the guide →Function: useRoot()#
function useRoot<T>(factory): T;Defined in: useRoot.ts:49
Create a Retree-managed root that survives React Strict Mode's
double-invocation of useState/useMemo initializers.
Use this in place of useState(() => Retree.root(new Foo())).
Then pass into useNode or useTree.
Type Parameters#
| Type Parameter |
|---|
T extends object |
Parameters#
| Parameter | Type | Description |
|---|---|---|
factory | () => T | function that returns a node wrapped in Retree.root. |
Returns#
T
a root proxied node.
Remarks#
Why: under Strict Mode, React invokes a useState lazy initializer twice
to detect impurity. Retree.root(...) mutates module-global state
(reproxyMap) keyed by raw object identity. When the constructor wraps
the same shared raw inputs (e.g., props passed from a parent) twice, the
second call overwrites entries the first instance depends on — and any
children parented to the first instance start reading stale state.
useRef is the only React init primitive that is not double-invoked
across the function body's StrictMode re-renders within a single mount,
so a useRef + null check guard ensures the factory runs exactly once.
Use useRoot when the Retree state belongs to this React subtree. Do not
use it for shared module-level state that should outlive the component;
create that root once outside React instead. Do not create a new Retree root
directly during render.
Example#
import { useNode, useRoot } from "@retreejs/react";
function CounterPanel() {
const counter = useRoot(() => ({ count: 0 }));
const state = useNode(counter);
return <button onClick={() => (state.count += 1)}>{state.count}</button>;
}