Migration from React
Migration from React: a worked guide from route registry through to a production build.
Example
Move local values to state, computed values to derive, and effect-owned asynchronous work to cancellable resources before changing routing or rendering mode.
import { derive, state } from '@askrjs/askr';
import { resource } from '@askrjs/askr/resources';
function ProjectPage({ initialProjectId }: { initialProjectId: string }) {
const [projectId] = state(initialProjectId);
const project = resource(({ signal }) => loadProject(projectId(), signal), [projectId]);
const title = derive(() => project.value?.name ?? 'Loading project');
return <h1>{title()}</h1>;
}Goal and architecture
The core mental shift moving from React is smaller than the getter/setter syntax suggests: Askr components do re-execute on every state change that they subscribe to, the same as a React function component re-renders — executeComponentSync calls the component function again and its return value is reconciled against the previous output, patching only the DOM that changed. What's different is subscription granularity, not execution model: a component only re-runs when a state()/derive() value it actually read last render changes, so a state update doesn't cascade into re-running parent or sibling components the way a React state update re-renders a whole subtree by default. derive() still avoids a manual dependency array because its sources are tracked automatically, and selector() narrows a subscription down to one equality check so a list item doesn't re-run for changes to the parts of a selection it doesn't care about — but the component itself is re-run, not patched node-by-node the way Solid does it.
Implementation
Where React code branches with {condition && <X/>} or ternaries, Askr provides <Show when={...}>, <Match>/<Case>, and <For each={...}> as components. For Show/Match, the main benefit over a plain conditional is mount/unmount lifecycle and a shared fallback shape, not a different update model — the containing component still re-runs and these still re-render their active branch along with it. For is the one control-flow component with real per-item behavior: it diffs children by key and patches, inserts, removes, or swaps individual DOM nodes without re-invoking the render callback for rows that didn't change, so a list update is closer to fine-grained than the rest of the runtime. Data fetching maps useQuery-style hooks onto createQuery/defineQuery, which return a query object with consistency, refreshing, and stale-reason fields instead of a { data, isLoading, error } tuple, and route-level data uses defer() plus <Resolve> in place of a Suspense boundary.
Failure states
The most common porting mistake is assuming Askr is Solid-style fine-grained reactivity because state() reads like a signal — it isn't. A state() write re-runs the owning component function, the same as a React setState call re-runs the function component; reading a stale destructured value from an earlier render is a bug in both frameworks for the same reason. What actually differs from React is *when* that rerun is scheduled and *what happens to its output*: there's no render phase separate from commit to schedule effects after, and the returned JSX is diffed against the previous tree by Askr's own reconciler rather than React's.
Verification
After porting a component, don't expect to see updates land on individual DOM nodes without the owning component's function running again — profile it and you should see the component function re-invoked on each state change it subscribes to, just less often than in an equivalent unoptimized React tree, since Askr doesn't cascade a rerun into components that didn't read the changed value. For-rendered lists are the exception worth profiling separately: confirm updating one item in a large list only touches that item's DOM node instead of re-invoking every row's render callback. Re-run existing behavioral tests (form submission, list filtering, route navigation) unchanged where possible, since Askr's @askrjs/askr/testing mocks are designed to slot into the same assertion style as React Testing Library patterns.