Guides · 09

SSR, testing and production

Server rendering, hydration, tests and the cleanup rules you can rely on.

Server rendering

Hook values render their initial value into the server markup, and animation continues after hydration. React 18 and newer use useId for stable variable names; on React 16 and 17 servers, pass an id.

app/layout.jsx
import { AnimatedProvider } from '@kkwaenggwari/animated';

// The package entry is marked 'use client'. A server layout can render the
// provider directly; hooks and Animated.<tag> go inside Client Components.
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <AnimatedProvider>{children}</AnimatedProvider>
      </body>
    </html>
  );
}

Stable ids on older React

Only needed when server rendering with React 16 or 17.

ssr.jsx
// React 18+ uses useId automatically. On React 16/17 servers, pass a stable id.
const progress = useAnimatedValue(0, { id: 'hero-progress' });

Cleanup you can rely on

Everything a component owns is released with it.

  • useAnimated, useAnimatedValue, useTimeline and useReorder stop their controllers and listeners on unmount.
  • Controllers and inputs declared in a useAnimated factory are replaced together when a dependency changes.
  • Animated.Keep removes departing children after their motion, and a new pose interrupts from the current position.
  • Outside React, bind, bindOutput, createTimeline and createLayoutScene return an explicit dispose.

Testing

flushAnimatedUpdates() applies pending output synchronously so deterministic tests can assert on the DOM.

Meter.test.jsx
import { flushAnimatedUpdates } from '@kkwaenggwari/animated';

act(() => progress.setValue(0.5));
flushAnimatedUpdates();
// Pending style writes are applied now; assert on the DOM.

Text, attributes and properties

output(target, mapping) inside useAnimated owns a style, attribute, text or object-property output. bindOutput attaches the same mapping immediately and returns flush and dispose.

Counter.jsx
const label = useRef(null);

const count = useAnimated(
  0,
  (value) => {
    output(label, { text: new AnimatedComputed([value], (v) => `${Math.round(v * 100)}%`) });
    timing(value, { toValue: 1, duration: 1200 });
  },
  [],
);

<span ref={label} />;

Search

Type to search the documentation.