상세 컨텐츠

본문 제목

React Router Transition 효과 적용

React/Router

by 일단두잇 2023. 1. 20. 17:08

본문

반응형

Router 이동시 마다 모바일과 같이 Transition 효과를 적용할수 있습니다.

TransitionGroup, CSSTransition 활용하여 2개 Layout이 움직이는 것처럼 효과를 주는 것이 가능합니다.

 

 

적용 순서

  1. TransitionGroup 정의
  2. CSSTransition 정의
  3. CSS 정의 : Route 및 Transition Class
  4. 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가 보여지는데까지 걸리는 시간
    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;
}
 
 

 

 

반응형

관련글 더보기

댓글 영역