この記事はプログラミング学習者がアプリ開発中に躓いた内容を備忘録として記事におこしたものです。内容に不備などあればご指摘頂けると助かります。
0.前提条件
この記事は以下の技術スタックを使用してGoogle Calendarを模したアプリを作った時に遭遇したエラーを解説するものです。
技術スタック
- Next.js ver 16.1.6
- TypeScript ver 5
- tailwindCSS ver 4.1.8
完成したアプリはVercelにデプロイして閲覧できるようにしました。
1.実装内容
// Linkコンポーネントで受け渡し対象のstate変数eventsを定義
import z from "zod";
// バリデーションメッセージの設定
export const eventSchema = z.object({
id: z.number(),
title: z
.string()
.min(1, { message: "入力必須です" })
.max(12, { message: "タイトルは12文字以内で入力してください" }),
date: z.string(),
});
type eventTypeZod = z.infer<typeof eventSchema>;
const [events, setEvents] = useState<eventTypeZod[]>([]);
// 受け取った日付の年・月と現在の年・月が同じかどうかを確認する
import { format, getMonth, getYear } from "date-fns";
type PropsType = {
today: Date;
signal: string;
};
const currentMonth = format(new Date(), "yyyy/MM");
export const compareDesignatedMonths = ({ today, signal }: PropsType) => {
if (format(today, "yyyy/MM") === currentMonth) {
return "/";
} else {
return `/month/${getYear(today)}/${getMonth(today) + 1}`;
}
};
<Link
suppressHydrationWarning
href={{
// compareDesignatedMonths関数は一つ上のコードウィンドウに記載
pathname: compareDesignatedMonths({
today: addMonths(today, -1),
signal: "<",
}),
query: {
receivedEvents: JSON.stringify(events),
today: addMonths(today, -1).toLocaleDateString(),
},
}}
>
<
</Link>
type PropsType = {
params: Promise<{ year: string; month: string }>;
searchParams: Promise<{ receivedEvents?: string; today: Date }>;
};
// 他のURLから遷移してきた時にクエリパラメーターからイベントを受け取り、JSONからオブジェクトに変換
const { receivedEvents } = React.use(searchParams);
const parsedEvents: eventTypeZod[] = receivedEvents
? JSON.parse(receivedEvents)
: [];
// 初期レンダリングでイベントが渡ってきていたらset関数で更新して表示に使う
useEffect(() => {
if (parsedEvents) {
setEvents(parsedEvents);
}
}, []);
遷移先にクエリパラメーターとしてreceivedEventsとtodayの2つの変数を受け渡す。
注意点として、クエリパラメーターでは文字列でしか扱えないので、eventsオブジェクトのような文字列以外はJSONに変えてから送る必要があります。受け取り先ではJSONからオブジェクトにJSON.parseで元に戻します。
※クエリパラメーターとはURLの中に文字列として含めて渡すことを意味します。
参考URL https://www.google.com?receivedEvents=[]&today=2026/02/23 とした場合、
?以降がクエリパラーメーターとなります。
2.useRouterを使った方法
Linkコンポーネント以外にページ遷移しながらデータを受け渡す方法としてuseRouterに辿り着きました。
以下のコード例はページの遷移を分岐させた実装です。
const router = useRouter();
const handleOptionChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
if (event.target.value === "month") {
if (checkDates) {
router.push(`/?receivedEvents=${JSON.stringify(events)}`);
} else {
router.push(
`/month/${passedYear}/${passedMonth + 1}?today=${today.toLocaleDateString()}&receivedEvents=${JSON.stringify(events)}`,
);
}
} else {
router.push(
`/week/${passedYear}/${passedMonth + 1}/${format(today, "dd")}?receivedEvents=${JSON.stringify(events)}`,
);
}
setSelectedOption(event.target.value);
};
但し、App Routerになってバージョンが最新のものになったなら、pathnameとqueryのプロパティが使えなくなっていましたので、Linkコンポーネントと同じように記述することはできないです。
代わりに上のコード例のように自分で?以降のクエリパラメーターを作ってあげることで同様の機能を実装できます。
削除については公式ページを参照 Using App Router, Latest Version 16.1.6として閲覧
useRouter
最後まで読んでいただきありがとうございます。