Skip to content

토스트 컴포넌트

eVe68 edited this page Aug 25, 2024 · 2 revisions

Issue

  • 사용자에게 알림을 줄 수 있는 토스트 구현
  • 사용자 입력에 반응해 즉시 띄울 수 있고 일정 시간이 지나면 완전히 사라지도록 구현하고자 함

발생한 이슈

tailwind CSS

  • const positionStyle = ${position}-${value}; 이런식으로 스타일을 적용하면 간헐적으로 적용됨
  • tailwind를 사용할 때 동적 string을 주면 안됨
  • const positionStyle = className[position][value]; 방식으로 미리 정의한 스타일을 객체에서 가져옴
export const className: Record<TailwindPosition, PositionValues> = {
  bottom: {
    0: "bottom-0",
    2: "bottom-2",
    4: "bottom-4",
    6: "bottom-6",
  },
  top: {
    0: "top-0",
  },
  "-bottom": {},
  "-top": {
    0: "-top-0",
    2: "-top-2",
    4: "-top-4",
    6: "-top-6",
    8: "-top-8",
    10: "-top-10",
    12: "-top-12",
    14: "-top-14",
  },
};

페이드 아웃 이후 요소 삭제

  • 투명도 조절로 요소를 제거하면 여전히 자리를 차지하는 문제
  • display none을 이용하여 렌더 트리에서 제거
  • 이미 렌더링 된 상태에서 css를 이용해 제거하는 것 이므로 리렌더링하지는 않음
  • visibility, display, opacity 그리고 조건부 렌더링

사용자 인터렉션에 따라 재생성

  • 동일한 오류 토스트를 반복적으로 띄우면 props가 동일해서 리렌더링이 일어나지 않음
  • 오류가 변경되어야만 오류 토스트가 다시 보이는 현상
  • key값을 계속 변경해 강제로 리렌더링이 되도록 함
    • 좋은 방법은 아닐 것이라고 생각함
    • 토스트 컴포넌트가 간단해서 큰 문제가 없을 것이라고 판단해 간단하게 생각하였음

구현한 토스트 컴포넌트

const Toast = ({
  content,
  position,
  value,
  delay,
  duration,
  color,
}: ToastInterface) => {
  const [isVisible, setIsVisible] = useState(true);
  const [isDisable, setIsDisable] = useState(false);

  useEffect(() => {
    const timer = setTimeout(() => {
      setIsVisible(false);
    }, delay);

    const animationTimer = setTimeout(() => {
      setIsDisable(true);
    }, delay + duration);

    return () => {
      clearTimeout(timer);
      clearTimeout(animationTimer);
    };
  }, []);

  if (isDisable) {
    return null;
  }

  const positionStyle = className[position][value];

  return (
    <div
      role="alert"
      className={`absolute z-10 ${positionStyle} left-1/2 h-fit w-fit -translate-x-1/2 whitespace-nowrap rounded-3xl ${color || "bg-tertiary"} px-6 py-3 font-kia-signature-bold text-body-1-bold text-gray-50 transition-opacity duration-700 ${
        isVisible ? "opacity-100" : "opacity-0"
      } ${isDisable ? "hidden" : ""}`}
    >
      {content}
    </div>
  );
};
Clone this wiki locally