Command Palette

Search for a command to run...

Hectal
Shots in this scene
SHOT 14.6Advanced ~18 min · shot 6 of 7

GSAP in React with useGSAP

In one line

useGSAP from @gsap/react is useEffect for GSAP: it runs your animation code in a scoped context after render and reverts it when the component updates or leaves, which also makes React's StrictMode double run harmless.

0/7 · 0%

Think of it like this

A hotel room. Each guest (a component) gets a room with their own things; at check-out the cleaners reset it. If the cleaners skip a room, the next guest finds the last one's music still playing. useGSAP is the cleaning schedule for GSAP animations in React components.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

useGSAP
A React hook from @gsap/react that runs GSAP code in a scoped, revertible context.
scope
A ref to the element that string selectors inside the hook are limited to.
contextSafe
A wrapper for event handlers so the tweens they start belong to the hook's context.
revertOnUpdate
An option that reverts the previous run when the dependencies change.

Step by step

01Count the runs in StrictMode

In "useGSAP in a component" the console prints effect run 1 and effect run 2. React ran the effect, reverted it, and ran it again. Three dots are found each time, because ".dot" is scoped to the component, and the second run starts from clean dots.

02Open the panel with a context-safe handler

Press Open the panel: it grows to 40 px over 0.4 s, and its label changes to Close. The handler is wrapped in contextSafe, so this tween is reverted if the component leaves.

03Compare the two hooks

In "useEffect against useGSAP" two lanes loop a dot. The console, 300 ms after mount, says there are 2 tweens on the useEffect dot and 1 on the useGSAP dot. The first one has two tweens fighting over x forever.

04Take StrictMode off

Without <StrictMode> the useEffect dot has 1 tween, not 2: the missing cleanup was always there.

Try it yourself

  1. 1

    Take StrictMode off

    In "useEffect against useGSAP" replace <StrictMode><App /></StrictMode> with <App />. The first line now reads tweens on the useEffect dot: 1: the leak only showed because StrictMode ran the effect twice. A component that remounts in production (a route change, a toggled panel) would leak the same way.

  2. 2

    Read the panel's height mid-move

    In "useGSAP in a component" pause, press Open the panel and step to 200 ms: the panel is 30 px tall (75% of the way, by power1.out), and 40 px at the end. It is a height tween (a layout property), fine for a small panel; for a big one use Phase 10's techniques.

Code & diagrams

useGSAP in a component

A scoped hook, dependencies with revertOnUpdate, and a context-safe click handler. The console shows StrictMode's double run.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.

Expected console output

effect run 1 | dots found: 3
effect run 2 | dots found: 3
useEffect against useGSAP

The same loop twice, in StrictMode. Count the tweens on each dot. The first lane's dot has two.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.

Expected console output

tweens on the useEffect dot: 2
tweens on the useGSAP dot: 1

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Start a tween from a click without contextSafe

Write onClick={() => gsap.to(".dot", { scale: 1.5, repeat: -1, yoyo: true })} and then remove the component.

terminal
$ Remove the component, then count tweens whose element is no longer on the page
── what you'll see ──
orphans 1 (the tween from the plain handler keeps running; the contextSafe handler's tween is gone)

Myth vs fact

Myth

A useEffect is enough for GSAP in React.

Fact

It works only if you return a cleanup that reverts a context. useGSAP does that for you, plus scoping and context-safe handlers.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    useGSAP uses useLayoutEffect in the browser (useEffect on the server), so a from() inside it writes its start state before the first paint: no flash of the finished state.

Remember this

  1. 1

    The problem this solves: React creates and removes elements all the time, and in development StrictMode runs every effect twice to expose missing cleanup. A useEffect that starts a tween and returns nothing leaves a tween per run, and animations on removed elements keep running (Topic 14.5). Writing the context and revert by hand in every component is boilerplate.

  2. 2

    The hook. useGSAP(() => { … }, { scope: ref, dependencies: [x], revertOnUpdate: true }). The callback runs in a layout effect (after the DOM update, before paint) inside a gsap.context scoped to the ref's element, so ".dot" means a .dot inside this component. With no dependencies it runs once after mount, and the context is reverted on unmount.

  3. 3

    Dependencies. When dependencies change, the callback runs again. The earlier animations are reverted only on unmount, so a new tween can stack on the old. revertOnUpdate: true reverts the previous run first, like a useEffect cleanup: use it when the callback builds everything from state.

  4. 4

    **Event handlers need contextSafe.** Code that runs later, from a click, is outside the context, so its tweens would outlive the component. const { contextSafe } = useGSAP({ scope }) returns a wrapper: onClick={contextSafe(() => gsap.to(…))} adds the handler's tweens to the context.

  5. 5

    StrictMode. In development React mounts, unmounts and mounts again. useGSAP reverts the first run before the second; a useEffect with no cleanup leaves two tweens (the second example counts them). Production runs effects once, so the leak hides until a component remounts.

Explain it without notes

01

Why does a useEffect that starts a GSAP tween leak in StrictMode, and how does useGSAP fix it?

02

What do scope, dependencies, revertOnUpdate and contextSafe do?

Practice

01

Write a Card component that fades its .line children in once on mount, scoped to the component.

02

Add a button to it that replays the animation on click, safe to unmount.

Done when you can

  • You use useGSAP with a scope ref instead of a bare useEffect

  • You wrap event-handler animations in contextSafe

  • You can explain what StrictMode's double run shows