React/Router
React Router Transition 효과 적용
일단두잇
2023. 1. 20. 17:08
반응형
Router 이동시 마다 모바일과 같이 Transition 효과를 적용할수 있습니다.
TransitionGroup, CSSTransition 활용하여 2개 Layout이 움직이는 것처럼 효과를 주는 것이 가능합니다.
적용 순서
- TransitionGroup 정의
- CSSTransition 정의
- CSS 정의 : Route 및 Transition Class
- router back 감지
1. TransitionGroup
- className : TransitionGroup CSS class명을 지정
<TransitionGroup className={`transitions-wrapper-right`}>
...
</TransitionGroup>
2. CSSTransition
-
- key : 해당 Key로 해당 Route를 찾아서 Transition 효과를 적용함
- useLocation을 이용하여 현재 path를 key 로 설정
- className : 실제 Transition효과가 발생하는 CSS class명을 지정
- timeout : 다음 Route가 보여지는데까지 걸리는 시간
- key : 해당 Key로 해당 Route를 찾아서 Transition 효과를 적용함
const location = useLocation();
...
<TransitionGroup className={`transitions-wrapper-right`}>
<CSSTransition
key={location.pathname}
classNames="right"
timeout={300}
>
<Routes>...</Routes>
</CSSTransition>
</TransitionGroup>
3. index.css 정의 : Route 및 Transition Class
- 먼저 각 Route의 페이지들은 postion:absolute를 해야 겹치는 효과가 보이게 됩니다.
.container {
position: absolute;
...
}
- 다음 Route로 이동 : 오른쪽 화면 밖(100%)에서 가운데(0)로 이동
.right-enter {
transform: translateX(100%);
}
.right-enter-active {
z-index: 1;
transform: translateX(0%);
transition: transform 300ms ease-out;
}
- 이전 Route로 이동 : 오른쪽 화면 밖(100%)으로 이동
- 여기서 중요한점은 right-exit-active 클래스에 대한 정의도 필요하다는 점입니다.
- transition을 천천히 돌려보면 transition으로 이동된 class가 계속 동일한 class를 유지한다는 것을 알수 있습니다. (자세한 설명은 다른 글에서 설명)
.right-exit{
transform: translateX(0%);
}
.transitions-wrapper-left >.right-exit-active,
.transitions-wrapper-left >.left-exit-active {
transform: translateX(100%);
transition: transform 300ms ease-out;
}
4. router back 감지 : back 이벤트를 감지해서 transition class명을 변경
-
- onpopstate 이벤트로 window 뒤로가기 event를 체크
- isBack 변수를 true로 변경
- CSSTransition이 완료되면 isBack을 false로 변경
window.onpopstate = () => {
isBack = true;
};
...
const transitionName = isBack ? 'left' : 'right';
...
<TransitionGroup className={`transitions-wrapper-${transitionName}`}>
<CSSTransition
key={location.pathname}
classNames={transitionName}
timeout={300}
onExited={() => {
isBack = false;
}}
>
...
최종 Code
Router.jsx
const Router = () => {
window.onpopstate = () => {
isBack = true;
};
const location = useLocation();
const transitionName = isBack ? 'left' : 'right';
return (
<TransitionGroup className={`transitions-wrapper-${transitionName}`}>
<CSSTransition
key={location.pathname}
classNames={transitionName}
timeout={300}
onExited={() => {
isBack = false;
}}
>
{/* route정의는 js에서 배열로 관리 */}
<Routes location={location}>{getRoutes(routes)}</Routes>
</CSSTransition>
</TransitionGroup>
);
};
index.css
.container {
position: absolute;
background-color: #fff;
top: 0;
width: 100%;
height:100%;
}
.transitions-wrapper-left,
.transitions-wrapper-right {
overflow: hidden;
height: calc(var(--vh, 1vh) * 100);
width: 100vw;
}
.right-enter {
transform: translateX(100%);
}
.right-enter-active {
z-index: 1;
transform: translateX(0%);
transition: transform 300ms ease-out;
}
.right-exit{
transform: translateX(0%);
}
.transitions-wrapper-left >.right-exit-active,
.transitions-wrapper-left >.left-exit-active {
transform: translateX(100%);
transition: transform 300ms ease-out;
}
반응형