react-transition-group
은 react 에서 좀 더 쉽게 애니메이션 효과를 구현할 수 있는 라이브러리로, react의 라이프 사이클 메서드와 함께 작동하여 react 구성 요소 간의 변화를 감지하고, 변화에 대한 애니메이션을 적용할수 있다.
$ yarn add react-transition-group
$ yarn add -D @types/react-transition-group
react 컴포넌트가 mount
, unmount
, update
될 때 애니메이션을 적용할 수 있는 컴포넌트이다. react 라이프 사이클과 함께 작동하여 변화에 대한 애니메이션을 적용할 수 있다.
CSS animation
을 적용할 수 있는 컴포넌트이다. CSS class
를 추가, 제거 또는 변경하여 애니메이션을 적용할 수 있다.
다른 컴포넌트로 전환될 때, 애니메이션을 적용할 수 있는 컴포넌트이다. key prop
을 이용하여 현재 보이는 컴포넌트와 새로운 컴포넌트를 전환할 때 애니메이션을 적용할 수 있다.
리스트를 관리할 때 사용되며, 리스트에 새로운 아이템이 추가, 제거 또는 변경될 때 애니메이션을 적용할 수 있다. 리스트 아이템을 key prop
으로 구분하고, 이를 기반으로 애니메이션을 적용한다.
import { Transition } from 'react-transition-group';
export default function Index() {
const [isView, setIsView] = useState(false);
const defaultStyle = {
transition: `opacity 300ms ease-in-out`,
};
const transitionStyles: Record<TransitionStatus, CSSProperties> = {
entering: { opacity: 1 },
entered: { opacity: 1 },
exiting: { opacity: 0 },
exited: { opacity: 0 },
unmounted: { opacity: 0 },
};
return (
<S.Wrap>
<S.Button onClick={() => setIsView((prev) => !prev)}>toggle</S.Button>
<Transition in={isView} timeout={300} mountOnEnter unmountOnExit>
{(state) => (
// state: ** -> entering -> entered -> exiting -> exited -> **
<S.Box style={{ ...defaultStyle, ...transitionStyles[state] }}>Animation Box</S.Box>
)}
</Transition>
</S.Wrap>
);
}
entering
, entered
, exiting
, exited
, unmounted
가 존재한다.in
값에 따라 state
상태값이 변경된다.true
: entering -> enteredfalse
: exiting -> exited"timeout" : 전환 효과가 재생되는 시간
"mountOnEnter" : 해당 옵션이 존재시 in
값이 true
가 되야만 렌더링 (이 옵션이 없다면 초기값이 false
일때도 dom tree에 존재하나 보이지만 않음)
"unmountOnExit" : 해당 옵션이 존재시 in
값이 false
가 될때, dom tree에서도 제거 (이 옵션이 없다면 true -> false
로 변경시 보이지만 않을 뿐 여전히 dom tree에 존재)
"on${status}" : 해당 상태로 변경된 직후 실행되는 함수
import { CSSTransition } from 'react-transition-group';
import './Transition.css';
export default function Index() {
const [isView, setIsView] = useState(false);
return (
<S.Wrap>
<S.Button onClick={() => setIsView((prev) => !prev)}>toggle</S.Button>
<CSSTransition in={isView} classNames="opacity" timeout={300} mountOnEnter unmountOnExit>
<S.Box>Animation Box</S.Box>
</CSSTransition>
</S.Wrap>
);
}
위의 Transition
컴포넌트 사용법과의 가장 큰 차이점은 classNames
를 props로 받는다는 것이다.
in
, classNames
의 값에 따라 다음과 같은 순으로 class
명이 변경된다
${classNames}-enter
-> ${classNames}-enter-active
-> ${classNames}-enter-done
-> ${classNames}-exit
-> ${classNames}-exit-active
-> ${classNames}-exit-done
이러한 class에 맞춰서 아래와 같이 css
를 작성하여 import해 사용하였다.
.opacity-enter {
opacity: 0;
}
.opacity-enter-active {
opacity: 1;
transition: opacity 0.3s;
}
.opacity-exit {
opacity: 1;
}
.opacity-exit-active {
opacity: 0;
transition: opacity 0.3s;
}
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import './Transition.css';
export default function Index() {
const [boxes, setBoxes] = useState<number[]>([]);
const addBox = () => setBoxes((prev) => [...prev, Math.random()]);
const deleteBox = (i: number) => setBoxes((prev) => prev.filter((_, idx) => idx !== i));
return (
<S.Wrap>
<S.Button onClick={addBox}>add</S.Button>
<TransitionGroup className="boxes">
{boxes.map((box, idx) => (
<CSSTransition key={idx} timeout={300} classNames="list">
<S.Box onClick={() => deleteBox(idx)}>{box}</S.Box>
</CSSTransition>
))}
</TransitionGroup>
</S.Wrap>
);
}
리스트를 그룹화하여 요소가 추가, 삭제 될때 리스트 요소에 대해 애니메이션을 적용한다.
따로 in
을 작성하지 않아도 된다.
.list-enter {
transform: translateY(-20%);
opacity: 0;
}
.list-enter-active {
transform: translateY(0);
opacity: 1;
transition: all 0.3s;
}
.list-exit {
transform: translateY(0);
opacity: 1;
}
.list-exit-active {
transform: translateY(-20%);
opacity: 0;
transition: all 0.3s;
}
여긴 잘 안써서, 나중에 쓸일 있으면 작성...