리액트 컴포넌트 마운트 효과
리액트는 다른 페이지의 이동 없이 처음 접속한 페이지에서 새로운 컴포넌트가 계속 바뀌며 한 페이지에 머무르게 됩니다. 또한 사용자가 요청한 페이지는 로딩 없이 그 자리에서 화면이 바뀌기 때문에 정말 시원한 느낌의 사용자 경험을 제공하기도 합니다. 리액트로 개발된 쇼핑몰의 경우 제품 판매가 더욱 증가했다는 이야기도 들려옵니다.
본론으로 리액트는 컴포넌트가 마운트되어 새롭게 렌더링 될 때 다음 화면이 화면에 순식간에 나타납니다. 저는 갑자기 바뀌는 화면이 심심하게 느껴져 렌더링 될 때 애니메이션 효과를 주고 싶어 방법을 모색해봤습니다.
개인적으로 좋아하는 3가지 효과를 만들어 봤고 움짤이랑 코드도 첨부해 놨습니다.
CSS Animation - @keyframe 사용하기
1. 페이드인(Fade-In) 효과
.mount1{ animation: 0.7s ease-in-out loadEffect1; }
@keyframes loadEffect1 {
0%{
opacity: 0;
}
100%{
opacity: 1;
}
}
적용 방법은 효과를 줄 컴포넌트 상위 HTML요소에 className으로 지정해주면 됩니다.
<div className="mount1">
<h2>풍부하게 가진 청춘을 구하지 사람은 보내는 것이다.</h2><br/>
<p>위하여서 생명을 관현악이며, 무엇을 그들은 대한 보는 가는 것은 때문이다. 인류의 청춘 더운지라 평화스러운 얼음에 자신과 현저하게 것이다. 하는 창공에 할지니, 작고 주며, 피가 것이다. 이상은 할지라도 길지 역사를 위하여, 이성은 봄바람이다. 그들은 끓는 위하여서, 주는 이것을 목숨이 인도하겠다는 철환하였는가? 이성은 우는 위하여 귀는 물방아 피다. 길지 들어 남는 방황하였으며, 수 것은 평화스러운 청춘의 것이다. 커다란 생생하며, 하였으며, 없으면 약동하다. 모래뿐일 수 앞이 끓는 피가 듣기만 보라. 찾아 가치를 남는 피고 오직 것이다. 그것을 이것이야말로 앞이 심장은 하는 새가 봄날의 때문이다.</p>
</div>
2. 슬라이드(Slide) 효과
.mount2{ animation: 0.6s ease-in-out loadEffect2; }
@keyframes loadEffect2 {
0%{
opacity: 0;
transform: translateX(-30px);
}
50%{
opacity: 0.5;
transform: translateX(30px);
}
100%{
opacity: 1;
transform: translateX(0px);
}
}
3. 줌인(Zoom-In) 효과
.mount3{ animation: 0.6s ease-in-out loadEffect3; }
@keyframes loadEffect3 {
0%{
opacity: 0;
transform: scale(0.7);
}
65%{
opacity: 0.65;
transform: scale(1.01);
}
85%{
opacity: 0.85;
transform: scale(0.97);
}
100%{
opacity: 1;
transform: scale(1);
}
}
리액트 애니메이션 라이브러리로는 react-spring, react-transition-group 등이 있습니다. 이제는 반대로 컴포넌트가 언마운트될 때, 애니메이션을 구현하는 방법입니다.
import React, { useState } from 'react';
const Container = () => {
const [mount, setMount] = useState(false);
const [effect, setEffect] = useState('mount1');
const onClickBtn = () => {
if(mount){
setEffect('unmount');
setTimeout(()=>{
setMount(v=> !v);
}, 400)
}else{
setEffect('mount1');
setMount(v=> !v);
}
};
return(
<>
<div className="container">
<div className="container-wrap">
<button type="button" onClick={onClickBtn}>Mount</button>
{mount ?
<div className={`box-wrap ${effect}`}>
<h2>풍부하게 가진 청춘을 구하지 사람은 보내는 것이다.</h2><br/>
<p>위하여서 생명을 관현악이며, 무엇을 그들은 대한 보는 가는 것은 때문이다. 인류의 청춘 더운지라 평화스러운 얼음에 자신과 현저하게 것이다. 하는 창공에 할지니, 작고 주며, 피가 것이다. 이상은 할지라도 길지 역사를 위하여, 이성은 봄바람이다. 그들은 끓는 위하여서, 주는 이것을 목숨이 인도하겠다는 철환하였는가? 이성은 우는 위하여 귀는 물방아 피다. 길지 들어 남는 방황하였으며, 수 것은 평화스러운 청춘의 것이다. 커다란 생생하며, 하였으며, 없으면 약동하다. 모래뿐일 수 앞이 끓는 피가 듣기만 보라. 찾아 가치를 남는 피고 오직 것이다. 그것을 이것이야말로 앞이 심장은 하는 새가 봄날의 때문이다.</p>
</div>
:
<></>
}
</div>
</div>
</>
)
}
export default Container;
.mount2{ animation: 0.6s ease-in-out loadEffect2; }
@keyframes loadEffect2 {
0%{ opacity: 0;
transform: translateX(-30px);
}
50%{
opacity: 0.5;
transform: translateX(30px);
}
100%{
opacity: 1;
transform: translateX(0px);
}
}
.unmount{ animation: 0.5s ease-in-out unloadEffect; }
@keyframes unloadEffect {
0%{
transform: translateX(0px);
opacity: 1;
}
100%{
transform: translateX(-30px);
opacity: 0;
}
}
버튼이라는 트리거가 있어 사라질 때에도 효과를 주기 쉽습니다. CSS속성인 opacity를 0으로 주고 애니메이션이 끝나는 시간을 계산해서 setTimeout 으로 컴포넌트를 언마운트 시켜주면 간단합니다.
리액트 라우터를 사용한다면 트리거를 걸어주기 어려우므로 Ract Transition Group을 사용하는 편이 좋습니다.