I want to create an alert component that all routes can use. Only one alert can be displayed at a time and it will always be in the same position regardless of the current route. Additionally, I should be able to close the current alert without preventing future alerts from popping up. What I've done is place the Alert component as a child of the root layout
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${inter.className} bg-black text-white`}>
{children}
<Suspense>
<Alert>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth="1.5"
stroke="currentColor"
height="24"
width="24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M6 18 18 6M6 6l12 12"
/>
</svg>
</Alert>
</Suspense>
</body>
</html>
);
}
Instead of using useState and passing the setter to all the components that need it which would turn everything into client components, I decided I will read the error param from the search params. I can close the alert by setting the error param to none.
export default function Alert({ children }: { children: React.ReactNode }) {
const searchParams = useSearchParams();
const pathName = usePathname();
const router = useRouter();
const error = searchParams.get('error');
if (error) {
const closeAlert = () => {
const newParams = new URLSearchParams(searchParams);
newParams.delete('error');
router.push(`${pathName}?${newParams.toString()}`);
};
return (
<AlertBody className="bg-red-600" message={error} closeAlert={closeAlert}>
{children}
</AlertBody>
);
}
return;
}