# Migration from React

> Migration from React: a worked guide from route registry through to a production build.

Source: [https://askrjs.com/docs/guides/migration-from-react](https://askrjs.com/docs/guides/migration-from-react)

Status: stable. Packages: @askrjs/askr.

**Published packages are authoritative.** Examples may lag behind a published contract. When guidance differs, verify the exports and TypeScript declarations in your installed package, then file an issue.

## Example

Move local values to state, computed values to derive, and effect-owned asynchronous work to cancellable resources before changing routing or rendering mode.

```tsx
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.

## Documentation navigation

[Previous](https://askrjs.com/docs/guides/production-readiness/index.md) | [Next](https://askrjs.com/docs/reference/index.md)
