최종 프로젝트 - tailwind로 toast 알림창 만들기

하영·2024년 11월 4일
1

팀프로젝트

목록 보기
22/27

Next.js 14 와 Toast Library의 오류

원래는 toast 라이브러리로 만들 생각이었는데 이상하게 자꾸만 toasat css 쪽에서 에러가 발생했다.

경고문구는 아래와 같았다.

/_next/static/css/app/ReactToastify.css.map 404

새 라이브러리를 찾아서 Next.js app router 버전과 잘 맞는지 등등 따져보기엔 시간도 부족하고 주 기능도 아니라 해결법이 없다면 tailwind 로 만들어야겠다고 생각했다.

오류 개선을 위해 실행한 방법들 😭

구글링해보니까 나와 비슷한 문제를 겪는 사람들이 많았다. 세가지 정도를 해봤는데 결과적으로 다 실패해버렸다...🥹

첫번째로 시도한 방법 - import 위치 바꾸기 🚧

출처 : https://stackoverflow.com/questions/77152572/reacttoastify-css-map-not-found-next-13-app-folder

나와 똑같은 Next.js 14 (App Router) 로 작업하던 사람이 라이브러리 토스트를 import 할 때 위치를 바꿔봤더니 해결되었다고 해서 나도 동일하게 옮겨주었다. 하지만 여전히 똑같은 문제가 발생했다. 🤯

두번째로 시도한 방법 - root layout으로 옮기기 🚧

출처 : https://github.com/fkhadra/react-toastify/issues/1099

이번에는 Toast Library의 위치도 여기저기 옮겨봤는데 여전히 동일한 에러가 뜨거나 esm.mjs.map 404 에러가 났다.

세번째로 시도한 방법 - 버전 낮추기 🚧

rm -rf node_modules
yarn 

yarn add react-toastify@7.0.3

라이브러리 버전을 낮췄더니 해결되었다는 글도 봐서 기존에 설치했던 라이브러리 버전도 지우고 새로 설치해보았지만 역시 문제는 동일하게 발생했다..ㅠㅠ


tailwind 로 토스트 알림창 구현하기

결국 일반 컴포넌트처럼 만들어서 구현하기로 하고 빠르게 작업을 실행했다.
복잡할 줄 알았는데 다행히 금방 만들 수 있었다.

01. 컴포넌트로 Tailwind Toast 작성하기

"use client";

import { useEffect } from "react";
import { useRouter } from "next/navigation";

interface CustomToastProps {
  message: string;
  onMove: () => void;
}

const CustomToast: React.FC<CustomToastProps> = ({ message, onMove }) => {
  const router = useRouter();

  // 일정 시간이 지나면 자동으로 닫히도록 설정 ⭐️
  useEffect(() => {
    const timer = setTimeout(onMove, 3000); // 3초 뒤에 사라짐
    return () => clearTimeout(timer);
  }, [onMove]);

  const handleRedirect = () => {
    onMove();
    router.push("/scraps");
  };

  return (
    <div className="fixed bottom-5 right-5 z-50 flex w-1/2 items-center justify-between space-x-4 rounded bg-gray-800 p-4 text-white shadow-md">
      <p>{message}</p>
      <button onClick={handleRedirect} className="font-semibold text-orange-500 hover:underline">
        스크랩 이동
      </button>
    </div>
  );
};

export default CustomToast;

02. 컴포넌트 적용하기

"use client";

import { useState, useEffect } from "react";
import CustomToast from "@/components/scraps/CustomToast"; // ✅ 토스트 컴포넌트 import


const ScrapButton = ({ postId }: { postId: string }) => {
  const [showToast, setShowToast] = useState(false); // ✅ 토스트 알림창 상태관리
  const { userId, folderName, setFolderName, isSaving, setIsSaving } = useScrapStore();
  const { existingFolders, saveScrap, useFetchScrapCount, isAlreadyScrapped } = useScrapData();


  // 저장 성공 시 토스트 표시
  const handleSaveComplete = async () => {
    setIsSaving(true);
    try {
      const savedSuccessfully = await saveScrap({ recipeId: postId, folderName });
      if (savedSuccessfully) {
        setIsScrapped(true);
        setShowToast(true); // ✅ 스크랩 성공하면 토스트 등장
      }
    } catch (error) {
      console.error("스크랩 저장 오류:", error);
    } finally {
      setIsSaving(false);
      setIsModalOpen(false);
      setTimeout(() => setShowToast(false), 3000);
    }
  };

  return (
    <div>
      <div className="flex cursor-pointer" onClick={handleMarkClick}>
        <Image src={isScrapped ? scrapFill : scrapEmpty} alt="스크랩 버튼" width={18} height={18} />
        <span className="ml-2 text-sm font-medium text-gray-700">{scrapCount || 0}</span>
      </div>

      {/* 모달 컴포넌트 */}
      {isModalOpen && (
        <ScrapModal
          isSaving={isSaving}
          folderName={folderName}
          existingFolders={existingFolders || []}
          onFolderNameChange={setFolderName}
          onSave={handleSaveComplete}
          onClose={() => setIsModalOpen(false)}
          onFolderClick={handleFolderClick}
        />
      )}

      {isLoginModal && <LoginCheckModal onClose={() => setIsLoginModal(false)} />}

      {showToast && <CustomToast message="스크랩 되었습니다." onMove={() => setShowToast(false)} />} 
    </div>
  );
};

export default ScrapButton;

일부 로직은 삭제했지만 아무튼 북마크를 클릭했을 때 성공하면 해당 토스트 알림창이 나오도록 적용해주었다.

결과확인

스크랩 성공하면 이렇게 알림창이 나오고 스크랩 이동 버튼을 눌렀을 때 페이지이동도 잘 되었다 👏

profile
왕쪼랩 탈출 목표자의 코딩 공부기록

0개의 댓글

관련 채용 정보