В блоге Build UI показали пример, как, используя React Server Components, показывать всплывающие сообщения (тосты) на клиенте. В примере используются серверные функции, куки и useOptimistic. По итогу, чтобы вызвать тост на клиенте, достаточно в любой серверной функции сделать вызов функции
toast, пример:
"use server";
export async function save() {
await toast("Blog post successfully saved!");
}
Функция toast выглядит следующим образом:
"use server";
import { cookies } from "next/headers";
async function toast(message: string) {
const cookieStore = await cookies();
const id = crypto.randomUUID();
cookieStore.set(`toast-${id}`, message, {
path: "/",
maxAge: 60 * 60 * 24, // 1 day
});
}
Используется случайный ID в названии куки для того, чтобы гарантировать уникальность названия куки.
Чтобы отображать куки на клиенте, надо считать куки, отфильтровать по префиксу
toast:
import { cookies } from "next/headers";
import { ClientToasts } from "./client-toasts";
export async function Toaster() {
const cookieStore = await cookies();
const toasts = cookieStore
.getAll()
.filter((cookie) => cookie.name.startsWith("toast-") && cookie.value)
.map((cookie) => ({
id: cookie.name,
message: cookie.value,
dismiss: async () => {
"use server";
const cookieStore = await cookies();
cookieStore.delete(cookie.name);
},
}));
return <ClientToasts toasts={toasts} />;
}
Как видно из кода выше, для удаления куки используется серверный API Next.js. Почему не использовать браузерное API для удаления? По мнению автора, работать с браузерным
document.cookie менее приятно, чем с API от Next.js. В ClientToasts автор использует хук useOptimistic, чтобы реализовать немедленное удаление тоста с экрана пользователя и отправить запрос на удаление куки на сервер:
export function ClientToasts({ toasts }: { toasts: Toast[] }) {
const [optimisticToasts, remove] = useOptimistic(toasts, (current, id) =>
current.filter((toast) => toast.id !== id),
);
const localToasts = optimisticToasts.map((toast) => ({
...toast,
dismiss: async () => {
remove(toast.id);
await toast.dismiss();
},
}));
return …
}
Одна из особенностей подхода хранения тостов в куках заключается в том, что тосты будут отображаться при редиректах, в новых вкладках и перезагрузках страницы.
https://buildui.com/posts/toast-messages-in-react-server-components