WEB/REACT

[REACT] react transition group /리액트 라우터에 애니메이션 주기, 슬라이드 애니메이션, 특정 페이지에만 라우트 애니메이션

자바칩 프라푸치노 2021. 8. 21. 19:51

react router에 tansition을 주고 싶어!

그래서 찾아봤던 것이 react-transition-group이다.

React-Router는 현재 경로가 바뀌면 즉이 DOM에서 제거하기 때문에 화면을 겹쳐서 애니메이션을 주려면 history가 바뀌기 전에 애니메이션을 실행시켜야한다. 공식적으로는 react-transition-group 사용을 권장한다.

리액트 공식 라이브러리이다.

공식문서가기

 

 

 

 

모든 페이지에 트랜지션 주기

일단 모든 페이지에 트랜지션을 주는 것은 쉽다.

 

TransitionGroup태그와

CSSTransition 태그를 Switch위에 감싸주면 된다.

라우터는 각각의 key를 갖게 되는데 그것을 pathname으로 준다.

key를 가진 라우터에게 classNames가 pageSlider인 css를 500ms초동안 지속한다.

그럼 pageSlider는 무엇이냐

import { ConnectedRouter } from "connected-react-router";
import { history } from "../redux/configStore";

import { Route, Switch, useLocation } from "react-router-dom";
import { TransitionGroup, CSSTransition } from "react-transition-group";
import "./Transition.css";


function App(props) {
 
  return (
    <ConnectedRouter history={history}>
        <TransitionGroup className="transition-group">
        <CSSTransition key={location.pathname} classNames="pageSlider" timeout={500}> 
        
          <Switch location={location}>
          <Route path="/" exact component={Home} />
          <Route path="/reviewdetail/:bookid/:reviewid" exact component={ReviewDetail}/>
          </Switch>
          </CSSTransition>
   		 </TransitionGroup> 
     </ConnectedRouter>
      
  );
}

export default App;

Transition.css에서 정의해놓은 클래스이다.

그리고 공식문서에도 나와있지만 TransitionGroup태그를 쓰려면

pageSlider뒤에 붙은 enter, enter-active, exit, exit-active를 써야한다.

마운트하기 시작할때, 마운트 다 했을때, 언마운트 시작할때, 언마운트 되고 나서를 의미한다.

body {
    overflow: hidden;
  }
  
  .transition-group {
    position: relative;
  }
  
  .pageSlider-enter {
    opacity: 0;
    transform: scale(1.1);
  }
  
  .pageSlider-enter-active {
    opacity: 1;
    transform: scale(1);
    transition: opacity 300ms, transform 300ms;
  }
  
  .pageSlider-exit {
    opacity: 1;
    transform: scale(1);
  }
  
  .pageSlider-exit-active {
    opacity: 0;
    transform: scale(0.9);
    transition: opacity 300ms, transform 300ms;
  }​

 

 

 

 

 

한 페이지만 트랜지션을 주고 싶은걸?

페이지마다 저렇게 transition이 일어나니까 굉장히 난잡했다.

그래서 한 페이지만 주고 싶었다.

그래서 열심히 구글링을 했다.

 

이번에는 Route를 감싸는 형식이 아니라 페이지 컴포넌트 자체에서 Transition을 주었다.

Transition을 최상단에 감싸고 그 안에는 하나만 리턴할 수 있다. 

지금 나는 Container만 리턴하고 있으니 그 안에 모든 자식 요소가 들어가야한다는뜻

 

여기서 status는 이 컴포넌트의 상태를 넘겨주는 것 같다.

마운트하고 있는지, 언마운트 하고 있는지.

//import 부분
...
import { Transition } from 'react-transition-group';
import "../shared/Transition.css";


const ReviewDetail = (props) => {
  ...

  
  return (
    <Transition in={true} timeout={200} appear>
      {(status)=>(
      <Container className={`pageSlider pageSlider-${status}`}> 
         ...
      </Container>
      )}
      </Transition>
  );
};

export default ReviewDetail;

 

여기서는 Transition 태그를 사용하는데 

그 경우에는 css에서 entering, entered,exiting,exited를 사용해야한다.

자세한건 공식문서에 있다.

.pageSlider-entering {
    opacity: 0;
    /* transform: scale(1.1); */ 
    transform: translate3d(100%, 0,0);
    background: pink;
    animation-name: slidein 4s 1s;
    
  }

  .pageSlider-entered {
    opacity: 1;
    /* transform: scale(1);
    transition: opacity 300ms, transform 300ms; */
    transform: translate3d(0, 0,0);
    transition: all 500ms;
    background: black;
    animation-name: slidein 4s 1s;
  }
  
  .pageSlider-exiting {
    opacity: 1;
    /* transform: scale(1); */
    transform: translate3d(0, 0,0);
    background: blue;
  }
  
  .pageSlider-exited {
    opacity: 0;
    /* transform: scale(0.9);
    transition: opacity 300ms, transform 300ms;
    transform: translate3d(-100%, 0,0); */
    transition: all 700ms;
    background: purple;
  }

 

 

 

그러나 이렇게 하니까 뒷배경이 하얀색에 슬라이드가 되었다.

나는 겹쳐서 하고 슬라이드가 되었으면 좋겠는걸?

 

 

 

 

 

 

특정 페이지만 transition을 주고 싶은데 겹쳐서 슬라이드가 되고싶어!

그래서 몇시간동안 정말 찾아보았지만 적절한 예시를 찾지 못했다..

없을리가?!?!?

하지만 내가 구글링 실력을 더 키워야겠다..

그러다가 문제 해결력 좋은 팀원이 이렇게 하면 어떻겠냐고 말했다!

import { ConnectedRouter } from "connected-react-router";
import { history } from "../redux/configStore";

import { Route, Switch, useLocation } from "react-router-dom";
import { TransitionGroup, CSSTransition } from "react-transition-group";
import "./Transition.css";


function App(props) {
 
  return (
    <ConnectedRouter history={history}>
        <TransitionGroup className="transition-group">
      <CSSTransition exact key={location.pathname==="/postwrite"?location.pathname:null} classNames="slide" timeout={500}>
        
          <Switch location={location}>
          <Route path="/" exact component={Home} />
          <Route path="/reviewdetail/:bookid/:reviewid" exact component={ReviewDetail}/>
          </Switch>
          </CSSTransition>
   		 </TransitionGroup> 
     </ConnectedRouter>
      
  );
}

export default App;

 

바로 location.pathname에 조건부렌더링을 하는것이다.

오 ! 적용이 된다.

 

그리고 구글링을 하고 유튜브를 찾아보면서 겹치게 슬라이드 css 를 찾아냈다.

이때 주의할점은 겹치고 싶은 페이지 둘다 position이 absolute로 되어있어야한다.

  .slide-appear,
  .slide-enter {
    z-index:1;
    opacity: 0.9;
    /* transform: scale(1.1); */ 
    transform: translate3d(100%, 0,0);

  }
  .slide-appear-active,
  .slide-enter.slide-enter-active {
    opacity: 1;
    transform: translate3d(0, 0,0);
    transition: all 500ms;

  }
  
  .slide-exit {
    opacity: 1;
    transform: translate3d(0, 0,0);

  }
  
  .slide-exit.slide-exit-active {
    opacity: 0.9;
    transition: all 700ms;

  }

 

 

결과

 

 

 

 

 

 

 

그렇다면 Transition을 사용했을때 css잘못이 아니었을까?(겹쳐지기)

결론: 아님

이유: 아마도 이때는 라우트마다 key를 가지고 history가 사라지기전에 transition이 실행되는게 아니라 하나의 컴포넌트에만 transition을 줬기 때문에 그 전의 history가 이미 DOM에서 사라지고 난 후라서 그런것 같음

(아니라면 말해주십쇼)

 

 

 

 

 

 

 

참고한 자료들

https://baeharam.netlify.app/posts/react/React-페이지-전환-애니메이션-구현하기

https://webaura.tistory.com/entry/Reactjs-리액트에서-화면전환-애니메이션-react-transition-group

https://blog.logrocket.com/react-transition-group-examples-tutorial/

https://codesandbox.io/s/km4jyy4n0v?from-embed=&file=/music.js

https://medium.com/lalilo/dynamic-transitions-with-react-router-and-react-transition-group-69ab795815c9

https://github.com/nicgirault/dynamic-transitions/tree/master/src

https://medium.com/lalilo/dynamic-transitions-with-react-router-and-react-transition-group-69ab795815c9

https://www.youtube.com/watch?v=NUQkajBdnmQ

728x90