🍞
Next.js App routerでのReact-Toastifyの設定方法
(元記事はdev.toに投稿したこちらの記事です)
Toast UIのライブラリを入れるならとりあえずReact-Toastifyという方は多いのではないでしょうか。設定や使い方がシンプルで簡単なので自分も普段からとてもお世話になっています。
ただNext.jsのApp routerを使う時はちょっとしたワークアラウンドが必要になりますので、この記事で紹介したいと思います。
ToastContainerをラップするクライアントコンポーネントを作成
ToastContainerはクライアントコンポーネント内に配置されなければ動作しません。
Pages routerであればApp.tsxなどにそのまま配置しますが、App routerの場合ルートコンポーネントはapp/layout.tsxであり、このコンポーネントはサーバーコンポーネントです。
なので一旦クライアントコンポーネントでラップしてやる必要があります。
ToastProvider
というクライアントコンポーネントを作成し、その中にToastContainerを配置します。
(ちなみにlayout.tsxをクライアントコンポーネント化する方法もありそうですが...それは試せていません。試した方がいらっしゃればコメントなどで教えていただけると嬉しいです!)
"use client";
import "react-toastify/dist/ReactToastify.css";
import "../../app/globals.css";
import { ToastContainer } from "react-toastify";
interface ToastProviderProps {
children: React.ReactNode;
}
export default function ToastProvider({ children }: ToastProviderProps) {
return (
<>
{children}
<ToastContainer />
</>
);
}
ちなみにベースとなる設定やスタイルはこのコンポーネントで定義できます。以下はTailwind CSSを使用した例です。
"use client";
import "react-toastify/dist/ReactToastify.css";
import "../../app/globals.css";
import { ToastContainer } from "react-toastify";
interface ToastProviderProps {
children: React.ReactNode;
}
export default function ToastProvider({ children }: ToastProviderProps) {
const contextClass = {
success: "bg-blue-600",
error: "bg-red-600",
info: "bg-gray-600",
warning: "bg-orange-400",
default: "bg-indigo-600",
dark: "bg-white-600 font-gray-300",
};
return (
<>
{children}
<ToastContainer
toastClassName={(context) =>
contextClass[context?.type || "default"] +
" relative flex p-1 min-h-10 rounded-md justify-between overflow-hidden cursor-pointer"
}
bodyClassName={() => "text-sm font-white font-med block p-3"}
position="bottom-left"
autoClose={3000}
/>
</>
);
}
ToastProviderをapp/layout.tsxで使用する
あとはさきほど作成したToastProvider
をただルートレイアウトコンポーネントに配置すれば設定完了です。
import type { Metadata } from "next"
import { Inter } from "next/font/google"
import Favicon from "@/app/icon.ico";
import "./globals.css"
import ToastProvider from "@/lib/react-toastify/ToastProvider"
const inter = Inter({ subsets: ["latin"] })
export const metadata: Metadata = {
title: "Toast app",
description: "Toast app is just a sample app for demonstrating react-toastify library.",
icons: [{ rel: 'icon', url: Favicon.src }]
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className={inter.className}>
<ToastProvider>
{children}
</ToastProvider>
</body>
</html>
)
}
これで完了です!
あとは公式ドキュメントにある通り
toast('🦄 Wow so easy!', {
position: "top-right",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
theme: "light",
transition: Bounce,
});
のようにすればどこでもトーストを呼び出すことができます!
Discussion