---
title: How tap differs from React
description: The handful of behaviors that aren't quite React.
---

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.

```ts
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/composition#usetaproot) breaks this chain.
It creates a subtree boundary: everything below it re-renders independently, and
the parent does not re-render when the subtree updates. This is how you keep a
large tree efficient and how store libraries are built on tap.

## `useLayoutEffect` collapses onto `useEffect`

tap has a single effect primitive. `useLayoutEffect` is accepted (so React code
ports cleanly) but behaves like `useEffect` inside a resource.
