커스텀 훅으로 toast message를 추가하는 방법은 아래 포스팅 참고 ! https://cjy00n.tistory.com/210
[ React + Recoil ] ToastMessage 커스텀 훅 제작 (토스트메시지, useToastMessage)
Recoil으로 전역으로 상태를 관리하며 위처럼 토스트 메시지 띄우는 작업을 커스텀 훅을 만들어 구현해보고자 한다. 타임아웃을 기본값으로 3초를 설정하여, 생성 3초 후 자동으로 없어지도록 하
cjy00n.tistory.com
위 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 "
연속되어 메시지를 생성할 때 엄청 자연스럽지는 않지만,, 토스트 메시지 애니메이션 적용하기 성공!
'FRONTEND > HTML&CSS' 카테고리의 다른 글
[ CSS ] position : sticky 사용하기 ( 요소가 스크롤을 따라오게 하기 ) (0) | 2024.03.01 |
---|---|
[ HTML ] 모바일에서 input , textarea 입력 활성화 시 화면이 확대되는 이슈 ( meta name="viewport" 태그 ) (0) | 2024.02.25 |
[ 생활코딩 - WEB1] HTML & Internet (0) | 2022.12.07 |
[코드잇 - html/css 시작하기] 06. 여행 사이트 (0) | 2022.11.24 |
[코드잇 - HTML/CSS 시작하기] 5. 텍스트 스타일링 (0) | 2022.11.24 |