searchParamsのobjectを取得する方法
Next.js では useSearchParams という Hooks が提供されています。
で、こいつの仕様がなかなかの曲者でして。
まず使いどころ自体も結構難しく。
Container Components 側であれば Props で受け取るので使うこともなく、そもそもクライアントコンポーネントでしか使えないのですが。
Presentational Components 側で使おうとしても、Presentational Components と URL の Query を絡めるのは考え方としてどうなんだ?と思う部分もあり。
Presentational Components や Custom Hooks のやむを得ないケースで使用するに留めるのが無難かなというのが個人的な意見だったりします。
で、ここからが本題でして。
まず useSearchParams は以下のような使い方をするのですが。
"use client";
import { useSearchParams } from "next/navigation";
export default function SearchBar() {
const searchParams = useSearchParams();
const hoge = searchParams.get("hoge");
console.log(hoge);
// ...
}
この searchParams が URLSearchParams という非常にややこしい型となっています。
Next.js の場合は URLSearchParams から伸びている get 関数で特定の Query Parameter を取得するケースが多いと思います。
また上記の他に、すべての Query Parameters を取得したいケースがたまにあると思うのですが、これが意外とややこしかったりします。
で、結論から書くと、以下のような実装感になるのかなと。
"use client";
import { useSearchParams } from "next/navigation";
export default function SearchBar() {
const searchParams = useSearchParams();
const queryParams: Record<string, undefined | string | string[]> = {};
searchParams?.forEach((value, key) => {
queryParams[key] =
key in queryParams
? [queryParams[key], value]
.flat()
.filter((v): v is NonNullable<typeof v> => typeof v === "string")
: value;
});
console.log(queryParams);
// ...
}
やぼったいですね、不本意ながらって感じの実装感になってます。
ぐぐってみると以下のような実装パターンが見つかるのですが。
"use client";
import { useSearchParams } from "next/navigation";
export default function SearchBar() {
const searchParams = useSearchParams();
const queryParams = Object.fromEntries(searchParams);
console.log(queryParams);
// ...
}
上記の実装だと以下の問題が発生します。
- 型が
Record<string, string>
になってしまいundefined
とstring[]
には対応できない - Query Parameter が配列の場合、末尾の要素のみが string として格納される
ということで、愚直に実装するしかないのかなーという印象です。
なんでこんな面倒な感じなんですかね?
検索系などではよく使う実装感だと思うので、参考になりましたら。