[ Tailwind css] 사용자 정의 애니메이션 추가하기 ( fadeIn , fadeOut )
커스텀 훅으로 toast message를 추가하는 방법은 아래 포스팅 참고 ! https://cjy00n.tistory.com/210
위 gif처럼 메시지가 생성될 때 fade-in, 메시지가 사라질 때 fade-out이 되도록 tailwind css에서 애니메이션을 정의하고 추가해줄 것이다.
메시지가 생성될 때 fade-in 효과를 주고,
삭제하기 0.5초 전 fade-out 애니메이션이 실행되도록 할 것이다.
로직은 다음과 같다.
- tailwind.config.js에 fadeIn, fadeOut 애니메이션을 정의한다.
- toastMessage type에 isRemoving 속성을 추가해준다. ( 삭제 “중”인 메시지를 뜻함)
- useToast를 수정한다.
- addToast 함수에서 새 toast를 생성하면서 isRemoving 속성을 false로 설정해주고, removeToast 함수 호출을 0.5초 빨리 한다.
- removeToast 함수에서 이 함수가 호출되면 해당 토스트의 isRemoving 속성을 true로 변경해주고, 0.5초 뒤 배열에서 해당 토스트를 삭제한다.
- toastMessageItem 컴포넌트에서 isRemoving 값에 따라, 이 값이 true이면 fade-out 애니메이션을 적용하고, false이면 fade-in 애니메이션을 적용하도록 한다.
tailwind 애니메이션 정의
▼ tailwind.config.js
// ...
theme: {
extend: {
keyframes: {
fadein: {
"0%": {
opacity: "0.5",
transform: "translateY(-10px)",
},
"100%": {
opacity: "1",
transform: "translateY(0)",
},
},
fadeout: {
"0%": {
opacity: "1",
},
"100%": {
opacity: "0",
transform: "translateY(-10px)",
},
},
},
animation: {
fadein: "fadein 0.5s",
fadeout: "fadeout 1s",
},
},
},
//...
};
tailwind css에서 애니메이션을 적용하기 위해서는 tailwind.config.js 파일을 수정해주어야 한다.
theme > extend > keyframes 에 fadein, fadeout을 정의한다.
fadein
- 투명도 50%, y축이 -10px → 투명도 100%, y축이 0
- 생성 시 위에서 아래로 내려오면서 선명해지도록 한다.
fadeout
- 투명도 100% → 투명도 0%, y축이 -10px
- 사라질 때 점점 투명해지면서 위쪽으로 올라가도록 한다.
그 다음에, 애니메이션을 정의하기 위해
theme > extend > animation에 fadeout, fadein을 정의한다.
fadein
- 0.5초동안 실행된다.
fadeout
- 1초동안 실행된다. ( 처음에 0.5초로 설정했으나, 어색한 부분이 있어 1초로 수정함)
해당 애니메이션이 필요한 컴포넌트의 클래스명에 animate-fadein
, animate-fadeout
을 명시하여 사용할 수 있게 설정되었다.
toastMessage type 수정
▼ src/types/ToastMessage.ts
export default interface ToastMessage {
id?: number;
content: string;
type?: "default" | "success" | "error";
timeout?: number;
isRemoving?: boolean; // 삭제"중"임을 의미하는 isRemoving 추가
}
기존 ToastMessage type에 삭제”중”임을 의미하는 isRemoving을 추가한다.
useToast 수정
addToast 함수 수정
▼ src/hooks/useToast.tsx
const addToast = ({
content,
type = "default",
timeout = 2000,
}: ToastMessage) => {
const newToast = { id: Date.now(), isRemoving: false, content, type }; // isRemoving 추가
setToasts((prev) => [...prev, newToast]);
setTimeout(() => {
removeToast(newToast.id);
}, timeout - 500); // isRemoving 상태 0.5초
};
새 Toast를 생성하면서, isRemoving의 값을 false로 지정하여 생성한다. (newToast)
removeToast를 호출하는 시간을 timeout-500 ( 0.5초 빼기) 으로 수정하여, 0.5초동안 fadeout 애니메이션이 적용될 수 있도록 한다.
removeToast 함수 수정
▼ src/hooks/useToast.tsx
const removeToast = (id: number) => {
setToasts((prev) =>
prev.map((toast) =>
toast.id === id ? { ...toast, isRemoving: true } : toast
)
);
setTimeout(() => {
setToasts((prev) => prev.filter((toast) => toast.id !== id));
}, 500); // isRemoving 상태 0.5초 기다린 후 배열에서 삭제
};
removeToast 함수가 호출될 때 가장 먼저, 해당 토스트의 isRemoving을 true로 바꾼 뒤 setToast 해주어, 해당 토스트가 삭제”중”임을 의미하도록 한다.
0.5초 뒤에 toast 배열에서 해당 토스트를 삭제하고 setToast해주어 완전히 삭제되도록 한다.
⇒ 0.5초 동안은 삭제 예정이니까 애니메이션 실행해
⇒ 0.5초 후에는 진짜 삭제!
이런 느낌이다..
toastMessageItem 컴포넌트 수정
▼ src/components/Toast/ToastMessageContainer.tsx
{toasts &&
toasts.map(({ content, type, id, isRemoving }) => (
<ToastMessageItem
content={content}
type={type}
key={"toast" + id}
isRemoving={isRemoving} /* isRemoving 넘겨주기 */
/>
))}
먼저 , toastMessageItem 컴포넌트를 호출하는 toastMessageContainer 컴포넌트에서 isRemoving을 넘겨주도록 추가한다.
▼ src/components/Toast/ToastMessageItem.tsx
const ToastMessageItem = ({ type, content, isRemoving }: ToastMessage) => {
return (
<div className={`/* 다른 스타일 생략 */${isRemoving ? "animate-fadeout " : "animate-fadein "}}
/* ... */ />
스타일을 지정해주는 className에서 isRemoving 값이 true이면 fadeout 애니메이션을 실행하고, false일 경우에는 fadeIn 애니메이션을 실행하도록 지정해준다.
isRemoving ? "animate-fadeout " : "animate-fadein "
연속되어 메시지를 생성할 때 엄청 자연스럽지는 않지만,, 토스트 메시지 애니메이션 적용하기 성공!