This content originally appeared on Blog and was authored by Blog
React is a hugely popular framework choice, and as evidenced by many of the sites in our showcase - React and GSAP can be a powerful combination. However, utilizing GSAP in React requires a different way of thinking than a vanilla JS project.
We've written this guide to help you get started using GSAP within a React project. This is not a tutorial, so feel free to dip in and out as you learn, think of it as a collection of recommended techniques and best practices to use in your projects.
Why GSAP?
Animating with GSAP gives you unprecedented levels of control and flexibility. You can reach for GSAP to animate everything — from simple DOM transitions to SVG, three.js, canvas or WebGL — your imagination is the limit. More importantly, you can rely on us. We obsess about performance, optimizations and browser compatibility so that you can focus on the fun stuff. We've actively maintained and refined our tools for over a decade and there are no plans to stop. Lastly, if you ever get stuck, our friendly forum community is there to help.
Going forward we will assume a basic understanding of GSAP and React.
If you're just getting going with React, this tutorial from the React team is a great place to start.
Need a GSAP refresher? Take a break and read about tweens and timelines. We’ll be here when you get back.
Quick Links
- Getting set up
- Targeting a DOM element for animation
- Creating our first animation
- Targeting descendant elements
- Creating a timeline
- Controlling when React runs our animation with useEffect
- Reacting to changes in state
- Animating on interaction
- Avoiding flash of unstyled content (FOUC)
- Cleaning up
Online PlaygroundsOnline Playgrounds
Get started quickly by forking one of these starter templates:
Create a new React AppCreate a new React App
If you prefer to work locally, Create React App provides a comfortable setup for experimenting with React and GSAP.
To create a project, run:
npx create-react-app gsap-app cd gsap-app npm start
Once the project is set up we can install GSAP through npm,
npm i gsap
npm start
then import it into our app.
import React from "react";
import { gsap } from "gsap";
export default function App() {
return (
<div className="app">
<div className="box">Hello</div>
</div>
);
}
More detailed information about getting started with React
Additional GSAP installation documentation
Targeting elementsTargeting elements
In order to animate using GSAP we need access to the element in the DOM. Refs provide a way for us to interact with and store references to DOM nodes in a React component.
const boxRef = useRef();
return <div className="box" ref={boxRef}>Hello</div>;
Read more about refs in the React docs
Creating our first animationCreating our first animation
GSAP updates inline style properties, so it’s important to make sure the DOM has been rendered before trying to animate anything.
If we ask GSAP to animate an element that hasn’t been rendered, we’ll get this warning in the console.
GSAP target not found.
In order to avoid targeting a null element, we can use the useEffect
hook. This hook tells React that our component needs to do something after rendering.
function App() {
// store a reference to the box div
const boxRef = useRef();
// wait until DOM has been rendered
useEffect(() => {
gsap.to(boxRef.current, { rotation: "+=360" });
});
// DOM to render
return <div className="box" ref={boxRef}>Hello</div>;
}
In this example, React will first render the box element to the DOM, then GSAP will rotate the box 360deg.
Targeting descendant elementsTargeting descendant elements
gsap.utils.selector()
Creating a ref
for each and every element we want to animate can add a lot of noise to our code. We can avoid this by making use of GSAP’s selector utility to easily select descendant elements.
const el = useRef();
const q = gsap.utils.selector(el);
useEffect(() => {
// Target ALL descendants with the class of .box
gsap.to(q(".box"), { x: 100 });
}, []);
Forwarding refs
gsap.utils.selector()
will target all descendants in the component tree.
Within a component based system, you may need more granular control over the elements you're targeting. You can use ref forwarding to get access to specific nested elements.
Creating and controlling timelinesCreating a timeline
Up until now we've just used refs to store references to DOM elements, but they're not just for elements.
Refs exists outside of the render loop - so they can be used to store any value that you would like to persist for the life of a component. If you're coming from class based components, this should be familiar to you as it’s essentially the same as using ‘this’.
In order to avoid creating a new timeline on every render, it's important to create the timeline inside an effect and store it in a ref
.
function App() {
const el = useRef();
const q = gsap.utils.selector(el);
const tl = useRef();
useEffect(() => {
tl.current = gsap.timeline()
.to(q(".box"), {
rotate: 360
})
.to(q(".circle"), {
x: 100
});
}, []);
return (
<div className="app" ref={el}>
<Box>Box</Box>
<Circle>Circle</Circle>
</div>
);
}
This will also allow us to access the timeline in a different effect and toggle the timeline direction.
Controlling when React runs our animation.controlling when react runs our animation
By default useEffect
runs both after the first render and after every update. So every time our component’s state changes, it will cause a re-render, which will run our effect again.
We can control when useEffect
should run by passing in an array of dependencies. To only run once after the first render, we pass in an empty array.
// only runs after first render
useEffect(() => {
gsap.to(q(".box-1"), { rotation: "+=360" });
}, []);
// runs after first render and every time `someProp` changes
useEffect(() => {
gsap.to(q(".box-2"), { rotation: "+=360" });
}, [someProp]);
// runs after every render
useEffect(() => {
gsap.to(q(".box-3"), { rotation: "+=360" });
});
Reacting to changes in statereacting to changes in state
Now that we know how to control when an effect fires, we can use this pattern to react to changes in our component. This is especially useful when passing down props.
function Box({ children, endX}) {
const boxRef = useRef();
// run when `endX` changes
useEffect(() => {
gsap.to(boxRef.current, {
x: endX
});
}, [endX]);
return (
<div className="box" ref={boxRef}>{children}</div>
);
}
Animating on interactionAnimating on interaction
Interaction is one of the most exciting things about animating on the web! In order to hook into user interactions like hover, we can use callbacks.
const onEnter = ({ currentTarget }) => {
gsap.to(currentTarget, { backgroundColor: "#e77614" });
};
const onLeave = ({ currentTarget }) => {
gsap.to(currentTarget, { backgroundColor: "#28a92b" });
};
return (
<div className="box" onMouseEnter={onEnter} onMouseLeave={onLeave}>
Hover Me
</div>
);
Avoiding flash of unstyled content (FOUC)avoiding fouc
As useEffect
fires after the DOM has been painted, when fading in elements you may notice an undesired flash of unstyled content.
In order to avoid the flash, we can replace useEffect with useLayoutEffect. useLayoutEffect
functions exactly the same as useEffect
, but React doesn’t run it until the DOM has been painted.
useLayoutEffect
is especially useful when you need to make DOM measurements, so we highly recommend it when using our ScrollTrigger and FLIP plugins.
More information about useEffect vs useLayoutEffect.
Cleaning UpCleaning up
It’s a good idea to return a cleanup function in your effects to kill off any running animations and anything else that could cause a memory leak, like an event listener.
This is particularly important if an animation runs for a really long time, makes use of ScrollTrigger, or changes the state in a component.
useEffect(() => {
const animation1 = gsap.to(".box1", { rotation: "+=360" });
const animation2 = gsap.to(".box2", {
scrollTrigger: {
...
}
});
const onMove = () => {
...
};
window.addEventListener("pointermove", onMove);
// cleanup function will be called when component is removed
return () => {
animation1.kill();
animation2.scrollTrigger.kill();
window.removeEventListener("pointermove", onMove);
};
}, []);
We hope this article was helpful - If you have any feedback please leave us a comment below so we can smooth out the learning curve for future animators!
Feeling confident and want to learn more? Check out our follow up article - Advanced GSAP animations in React.
This content originally appeared on Blog and was authored by Blog
Blog | Sciencx (2021-08-17T16:09:00+00:00) GSAP + React, First Steps & Handy Techniques.. Retrieved from https://www.scien.cx/2021/08/17/gsap-react-first-steps-handy-techniques-2/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.