# How tap differs from React
URL: /tap/docs/tap/differences-from-react

The handful of behaviors that aren't quite React.

> For AI agents: a documentation index is available at [llms.txt](/llms.txt). Use `.md` for canonical markdown pages; `.mdx` is kept as a backwards-compatible alias on supported URL paths.

Resources are React hooks, so almost everything carries over: the rules of hooks, dependency arrays, memoization, refs, and effect cleanup all work as you expect. This page covers the few places tap deliberately differs.

## Effects run in call order

In React, effects run children-first (inside-out), because a component can only reach its children by returning them. In tap, `useResource` is just another hook, so **effects run in the exact order they are called**, and you can place effects before or after a child.

```
import { resource, useResource } from "@assistant-ui/tap";
import { useEffect } from "react";

const useParent = () => {
  useEffect(() => console.log("1: before child"));
  const child = useResource(Child());
  useEffect(() => console.log("3: after child"));
  return child;
};

const Parent = resource(useParent);

const useChild = () => {
  useEffect(() => console.log("2: child"));
};

const Child = resource(useChild);
// Mount order: 1, 2, 3
```

Cleanup on unmount runs in the same order (FIFO). This lets a parent run setup both before and after its children, which is useful when it reacts to data a child provides.

## The tree re-renders from the root

This is the biggest difference. In React, a state change re-renders only the component that changed and its descendants. In tap, **the whole resource tree re-renders from the root**: because a parent reads its child's return value directly, the parent must re-run to receive the new value, and so must its parent, all the way up.

[`useTapRoot`](/tap/docs/tap/trees-and-rerenders#separate-scheduling-with-usetaproot) breaks this chain by creating a new root with its own scheduler. Everything below it re-renders independently, and the parent does not re-render when that root updates.

## `useLayoutEffect` and `useInsertionEffect` collapse onto `useEffect`

tap has a single effect primitive. `useLayoutEffect` and `useInsertionEffect` are accepted (so React code ports cleanly) but behave like `useEffect` inside a resource.

## A throwing snapshot keeps the committed value

In React, when a store notifies `useSyncExternalStore` and `getSnapshot` throws, React re-renders and the error surfaces during that render. In tap, the resource keeps its last committed value and skips the re-render; the throw is swallowed for that notification only, and the next notification whose snapshot succeeds and differs re-renders as usual. This may change in a future release.