리액트-route transition animation (1)
밴드부 티켓 예매를 거의 휴대폰으로 할테니 웹이어도 앱느낌이 나게끔 기획을 했었다. 레이아웃을 휴대폰 레이아웃에 고정시키고 , 일정 범위 이상 화면이 크게되면 , 레이아웃이 더이상 늘어나지않게끔 디자인이되었다.
완성도를 높이기위해서 애니메이션을 넣고 싶었고, framer motion같은 것으로 구현을 할 까 하다가 react transition group 이란걸 알게되었다. Route를 사용한 애니메이션엔 가장 적절한 라이브러리가 아닐까 싶다. ( 하지만 도큐멘트로는 너무나도 부족하다. 유툽찾아보시는걸 추천드린다.)
우선 이글을 통해서 얻을 수 있는것을 알려드린다.
- react transition group 을 이용한 route 사이의 애니메이션을 넣는방법
- 양방향(왼쪽, 오른쪽)의 방향을 지원하는것이아닌 한쪽방향만으로의 애니메이션
양방향으로 페이지 네이션 하는 방법 ( 페이지 오더 관련) 은 2편을 기대해 주시기 바란다.
React transition animation
먼저 소스부터 던지고 가겠다. react router dom v6가면서 글자만 바뀌었지 형식은 비슷비슷 하다. (2) 편에서는 달라질 소스들이다 유의해 주시길 바란다. ( 원래소스가아니라 정리한소스다)
import { Routes, Route, useLocation } from 'react-router-dom';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
function Animation() {
const location = useLocation();
return (
<TransitionGroup className="transitions-wrapper" >
<CSSTransition
key={location.pathname}
classNames={"right"}
timeout={300}
>
<Routes location={location}>
<Route path="/test" element={<TestPage style={{ position: 'absolute' }}/>} />
<Route
path="/tickets/:ticketId"
element={<TicketCodePage style={{ position: 'absolute' }} />}
/>
</Routes>
</CSSTransition>
</TransitionGroup>
);
}
export default Animation;
TransitionGroup은 애니메이션과는 직접적으로 관련되어있지 않고 , 상태를 관리하는 느낌이다. 어떠한 상태가 변경되면 어떤 컴포넌트는 마운트 시키고, 어떤 컴포넌트는 언마운트 시키는(동시적으로) 작업관리자 느낌이라고 보면 좋을것 같다. 실제로 dom으로 div요소를 하나 만들기도 한다. 필자는 TransitionGroup 이 만든 div 요소에 클래스를 달아 css로 postion : relative 속성을 주었다. 그래야 자식 컴포넌트에서 absolute를 설정 할 수가 있다.
CSSTransition 은 실제로 애니메이션을 관리를 하는 것이다.
- <classNames>-enter
- <classNamse>-enter-active
- <classNames>-exit
- <classNames>-exit-active
위와 같이 enter , exit 두가지 상태와 보통인 상태와 active 된 상태가있는데
.transitions-wrapper {
position: relative;
overflow: hidden;
height: calc(var(--vh, 1vh) * 100);
width: 100vw;
}
.right-enter {
transform: translateX(100%);
}
.right-enter-active {
transform: translateX(0);
transition: transform 300ms ease-in-out;
}
.right-exit {
transform: translateX(0);
}
.right-exit-active {
transform: translateX(-100%);
transition: transform 300ms ease-in-out;
}
css 파일 같이 transtion 속성을 주게되면 그 차이를 이용해 애니메이션 효과가 보여지게 되는 것이다. 여기서 주의할점은 한번 enter를 한 컴포넌트가 다음엔 exit으로 바뀐다는것이다.
여기서 TransitionGroup이 필요한 이유가 나온다. 동시적으로 하나는 들어오고 하나는 나가는것을 구현할려면 즉 CSSTransition은 하나의 컴포넌트를 관리를 하니, TransitionGroup 컴포넌트를 이용을해서 하나의 컴포넌트가 들어오는 동안 다른 컴포넌트는 나가게 만들 수있는 것이다.
말로만 하면 이해가 잘 안갈테니 , 엘리먼트가 바뀌는것을 보아라
사실 위에 나온 소스 2개가 다 이고, 좀더 부가적인 설명을 해보겠다.
위에서 TransitionGroup 은 div 엘리먼트를 하나 만든다고 그랬다. 물론 해당속성을 없앨수 있지만, 자식 컴포넌트들을 absolute 설정을 해놓고 overflow를 hidden으로 해야 스크롤이 안생기고, 겹쳐서 보일수있기때문에 . 위 css 파일의 .transtions-wrapper을 참고하면 좋을 것 같다.
여기서 주의점은 routes에 location 을 주었다는것인데, 이유는 간단하다. Routes 는 여러분의 url이 변경되는 것을 자동으로 감지해서 랜더링 할것을 결정해주는데 만약 /test -> /test2 로 가는경우 Routes는 test2 만 해당하는 컴포넌트를 랜더링해주는것이다.
하지만 TransitionGroup을 사용하면 exit하는 놈, enter하는 놈 두가지가 있지않는가. 우리는 그래서 차후에 exit하는놈에게 이전 location 정보
를 라우트한테 넘겨준 상태로 남겨놔야 exit하는 놈을 제대로 표현해 줄 수있는것이다.
매우 간단하다. exit enter와 active를 이용해서 css를 직접 작성해줘야 애니메이션이 가능해진다는점.
CSSTransition에 한번은 enter을 하면 다음은 exit로 바뀌어진다는점.
그리고 classNames 속성은 그대로 유지된다는점.
location 객체를 넘겨줘야 exit할때 Routes가 이전상태를 기억한다는 점.
위주의점만 잘 기억하면서 작성하시면 될것같다.
2편에서는 양방향으로 페이지 네이션 하는 방법을 알려드리겠다.
2편 바로가기