[]previous and next page

Keys, renderId and what must match

A key starts with the renderId, then one number for each enclosing component call, then the number of the template root, all joined with - (0-0-0-0 above is…

For agentsUpdated

A key starts with the renderId, then one number for each enclosing component call, then the number of the template root, all joined with - (0-0-0-0 above is renderId 0, the Page call, the App call, the first template of App). Each component call opens a scope; components and template roots draw their numbers from that scope's counter in the order they run. Keys therefore depend on the shape of the tree and nothing else: not on owners, effects, timing or memos. Server and client agree as long as they run the same components with the same structure.

renderId defaults to "0". Give each render a different id when more than one is on a page (several independent apps, or fragments rendered by separate server calls), and pass the same value to hydrate. It may contain letters, digits, _ and -; anything else throws a TypeError.

render-id.tsxtsx
import { renderToString } from "@shadow-js/web/server";
import { Page } from "./src/app";

console.log(renderToString(() => <Page />, { renderId: "left" }));
Expected output
<main data-hk=

When the client disagrees with the server#

Hydration never leaves a half-hydrated tree. What the client does depends on the difference:

Difference Result
A text value differs the server's text node is reused and its data is overwritten; development warns HYDRATION_TEXT_MISMATCH with the expected and the server text (a region the server left empty claims no text and is not compared)
The server sent more list items than the client wants the extra elements are removed
The client wants an element the server did not send (no element for the key) HYDRATION_KEY_MISS warning in development; the element is created on the client
Wrong renderId, or no server markup at all every key misses; everything is created on the client and replaces the server markup

Treat a HYDRATION_KEY_MISS as a bug in your app, not as a recoverable condition: it means the server and client ran different code or different data. The usual causes are branching on window or Date.now() during render, data that differs between the two (a request-specific value that the client does not have), and a mismatching renderId.

A HYDRATION_TEXT_MISMATCH has the same causes for text: the client computed a different text for a region than the server wrote. Its warning shows both texts, escaped and cut to 40 characters.