greensock을 사용하는 이유?
스크롤 기반 애니메이션은 기본적인 CSS와 JS로 수행 가능해 애니메이션 라이브러리를 사용하는 것이 낭비라고 생각될 수 있습니다. 하지만 greensock을 사용하면 브라우저 버그나 불일치 등의 호환성 문제를 해결하고 애니메이션이 모듈화되어 코드의 가독성, 재사용성을 높일 수 있습니다. 또한, 스크롤 위치에 기반한 애니메이션은 성능상의 이슈가 있기 때문에 스크롤 이벤트가 너무 자주 발생하지 않도록 방지해야 하는데 매번 스크롤 리스너를 조절하는 것은 상당히 번거롭습니다. 그렇기 때문에 호환성, 사용성이 좋고 가볍게 최적화가 되어 있는 greensock 라이브러리를 사용했습니다.
라이브러리 설치
npm install gsap
import
gsap
와 ScrollTrigger
를 임포트 해줬습니다. ScrollTrigger
는 스크롤 기반 애니메이션을 위해 사용합니다. 일반적인 애니메이션은 gsap
만으로 충분합니다.
import gsap, { ScrollTrigger } from 'gsap/all';
DOM 요소 지정
GSAP 애니메이션을 사용하기 위해서는 DOM 요소에 접근할 수 있어야 합니다. 리액트 컴포넌트에서 DOM 요소에 접근하기 위해 useRef
를 사용해 DOM 요소를 참조하는 변수를 생성합니다.
const Greensock = () => {
const box1 = useRef();
return <img src={img1} alt="img1" ref={box1} />;
};
애니메이션 적용 및 CleanUp
GSAP 애니메이션을 적용하기 위해서 DOM 요소가 지정 되고 DOM이 랜더링 되어야 하기 때문에 리액트 컴포넌트에서는 랜더링 후 실행되는 useEffect
의 콜백 함수 안에서 애니메이션 적용이 이뤄져야 하고 CleanUp 함수에서 gsap 애니메이션을 삭제하여 메모리 누수를 방지합니다.
const Greensock = () => {
const box1 = useRef();
useEffect(() => {
let animation = gsap.to(box1.current, { rotation: "+=360" });
return () => {
animation.kill();
}
}, [])
return <img src={img1} alt="img1" ref={box1} />;
};
스크롤 트리거
스크롤 트리거는 다음과 같이 적용할 수 있습니다. 스크롤 트리거를 적용하고 markers
속성 값을 true
로 설정하면 위의 스크린샷과 같이 인디케이터를 표시해 애니메이션의 타이밍을 시각적으로 보다 예측하기 편하게 작업 할 수 있습니다. 작업 후 해당 속성은 삭제합니다.
// 스크롤 트리거 등록
gsap.registerPlugin(ScrollTrigger);
gsap.to(box.current, {
// 스크롤 트리거 적용
scrollTrigger: {
trigger: box.current,
toggleActions: 'play reset play reset',
markers: true,
start: 'top center',
end: 'bottom center',
},
x: 500,
});
toggleActions
toggleActions은 "onEnter, onLeave, onEnterBack, onLeaveBack" 네 가지로 구성됩니다. 스크롤과 요소의 위치에 기반해 조건에 맞는 액션이 실행되는 것 입니다.
onEnter
은 scroller-start
인디케이터가 start
를 지나 start
와 end
사이에 존재할 때,onLeave
는 scroller-end
인디케이터가 end
를 지나 start
와 end
사이를 벗어났을 때,onEnterBack
은 scroller-start
인디케이터가 start
를 지나 start
와 end
사이를 벗어났을 때,onLeaveBack
은 scroller-end
인디케이터가 end
를 지나 start
와 end
사이에 존재할 때를 뜻 합니다.
액션 키워드는 다음과 같습니다.
"play", "pause", "resume", "reset", "restart", "complete", "reverse", and "none".
설명을 위한 예시 코드입니다.
import React, { useEffect, useRef } from 'react';
import img1 from '../../images/img1.png';
import img2 from '../../images/img2.png';
import img3 from '../../images/img3.png';
import img4 from '../../images/img4.png';
import gsap, { ScrollTrigger } from 'gsap/all';
import styled from 'styled-components';
const Wrapper = styled.div`
display: grid;
padding: 100px 0;
`;
const Img = styled.img`
margin-bottom: 100px;
transition: 0.5s linear;
`;
const Greensock = () => {
const box1 = useRef();
const box2 = useRef();
const box3 = useRef();
const box4 = useRef();
useEffect(() => {
const boxes = [box1, box2, box3, box4];
const animations = new Array(4);
// 스크롤 트리거 등록
gsap.registerPlugin(ScrollTrigger);
boxes.forEach((box, idx) => {
animations[idx] = gsap.to(box.current, {
// 스크롤 트리거 적용
scrollTrigger: {
trigger: box.current,
toggleActions: 'play reset play reset',
markers: true,
start: 'top center',
end: 'bottom center',
},
x: 500,
});
});
return () => {
animations.forEach((animation) => animation.scrollTrigger.kill());
};
}, []);
return (
<Wrapper>
<Img src={img1} alt="img1" ref={box1} />;
<Img src={img2} alt="img2" ref={box2} />;
<Img src={img3} alt="img3" ref={box3} />;
<Img src={img4} alt="img4" ref={box4} />;
</Wrapper>
);
};
export default Greensock;
모든 애니메이션과 기능을 설명하기엔 GSAP의 기능이 정말 많기 때문에 기본적으로 리액트에 어떻게 적용하는지가 중요합니다. 기능 자체는 markes와 같은 속성이 있기 때문에 뷰를 직접 보면서 테스트하다 보니 점점 감을 잡아가는 것을 느낄 수 있었다.
참고자료
GSAP + React, First Steps & Handy Techniques.
ScrollTrigger 공식문서
[GSAP] 애니메이션 사용법 (기초)
[GSAP] 애니메이션 사용법 (중급 - ScrollTrigger)
'프로그래밍 공부 > React' 카테고리의 다른 글
[React] React Router v6 (0) | 2022.01.30 |
---|---|
[React] Youtube Player API 사용 및 에러 (0) | 2022.01.20 |
[React] SVG image 파일을 이용한 애니메이션 (0) | 2022.01.11 |
[React] 상태관리 Redux (0) | 2021.11.02 |
컴포넌트 디자인 & CSS 방법론 / TIL 34일차 (0) | 2021.10.27 |