Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Next.jsでクエリパラメータを楽に扱おう nuqsを紹介!
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
imaimai17468
September 06, 2024
2.1k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Next.jsでクエリパラメータを楽に扱おう nuqsを紹介!
imaimai17468
September 06, 2024
More Decks by imaimai17468
See All by imaimai17468
オートメーション・バカにならないために
imaimai17468
1
280
MVP先行の探索型DocDD
imaimai17468
1
180
コーディングチェックの自動化がしたい!
imaimai17468
4
1.2k
型パズルを好きになるために、競プロを型システムだけで解いてみることにした
imaimai17468
6
790
フロントエンド設計の所感 1年目
imaimai17468
0
97
Silk Weave -未来研究大会発表資料-
imaimai17468
1
59
TailwindCSSで学ぶ技術批判の気をつけ方
imaimai17468
8
7.1k
Next.js+yjs+BlockNoteでNotionライクな最高の共同編集エディタを作ろう
imaimai17468
0
3.3k
BlockNoteを布教するぜ
imaimai17468
0
72
Featured
See All Featured
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.6k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.3k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
118
120k
Google's AI Overviews - The New Search
badams
0
1k
How Software Deployment tools have changed in the past 20 years
geshan
0
34k
4 Signs Your Business is Dying
shpigford
187
22k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
250
1.3M
Everyday Curiosity
cassininazir
0
230
Code Reviewing Like a Champion
maltzj
528
40k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
We Have a Design System, Now What?
morganepeng
55
8.2k
Unsuck your backbone
ammeep
672
58k
Transcript
Next.jsでクエリパラメータを楽に扱おう nuqsを紹介! いまいまい 1
自己紹介 いまいまい (今井俊希) 株式会社ゆめみ 新卒 フロントエンドエンジニア 本編ではBlockNoteというライブラリで登壇 2
URLとクエリパラメータ、舐めたら死ぬ あぶない! <a href={`/hoge?huga=${piyo}&poyo=${fuga}`}>Link</a> URLを文字で扱うのは危険と言われがち URLクラスを使う URLSearchParamsクラスを使う 3
Next.jsでのクリパラメータでの扱い router.queryを使う const router = useRouter(); // ... router.push({pathname: "hoge",
query: {id: router.query.id}}); useSearchParamsを使う const searchParams = useSearchParams(); // ... <Link href={{pathname: "hoge", query: {id: searchParams.get("id")}}}> Link </Link> 4
クエリパラメータ管理の課題 1. 複数のクエリパラメータを管理したいとき 一部だけ更新して、一部は維持とか 2. stateとの同期 inputなどの状態との同期 queryからstateへの初期状態反映 3. queryのバリデーション
4. AppRouter / ServerComponentsへの対応 5
nuqsについて紹介 next-usequerystateの略 発音は“nukes”. [njuks] Next.jsにおけるクエリパラメータを型安全かつ直感的に扱えるようにする 6
nuqsの使い方 ボタンの状態をqueryを同期させる inputのstateがリアルタイムにqueryに反映される const [name, setName] = useQueryState('name', parseAsString.withDefault("")) //
... return ( <input value={name} onChange={e => setName(e.target.value)} /> ) 7
豊富なparserの種類 string number (integer, float, hex) boolean literal (string, numeral)
enum date & timestamp array json (with zod scheme) なんなら自分で作れる (createParser) 8
複数のqueryを定義したい場合 それぞれのqueryを非同期に更新できる const [isCheck, setIsCheck] = useQueryState('count', parseAsBoolean.withDefault(false)) const [name,
setName] = useQueryState('name', parseAsString) // ... return ( <div> <input value={isCheck} onChange={e => setName(e.target.value)} /> <input value={name || ''} onChange={e => setName(e.target.value)} /> </div> ) 9
Option パーサーに複数のオプションを渡すことができる parseAsString.withOptions({ history: 'push' }) history // 履歴が置き換えられる useQueryState('foo',
{ history: 'replace' }) // 新しく履歴が追加される useQueryState('foo', { history: 'push' }) historyのhackはbad UXにつながる可能性があるので注意 10
shallow クエリパラメータの更新によるルーティング範囲の切り替え useQueryState('foo', { shallow: true }) true クライアントで完結 false
サーバーまで通知されて、場合によっては再レンダリングされる queryによって即座にfetchさせたい場合など ハードナビゲーション 11
Serialize nuqsで定義したqueryを型安全にurl文字列で出力できる const searchParams = { search: parseAsString, limit: parseAsInteger,
sortBy: parseAsStringLiteral(['asc', 'desc'] as const) } const serialize = createSerializer(searchParams) serialize("/hoge", { search: 'foo bar', limit: 10, sortBy: 'asc' }) // -> /hoge/?search=foo+bar&limit=10&sortBy=asc 検索フォームなどは の関数をLinkコンポーネントで渡すだけでよくなる 12
Server Componentsでの利用 1. queryの定義・cacheとserializeの定義をする const searchParams = { q: parseAsString.withDefault(''),
maxResults: parseAsInteger.withDefault(10) } export const searchParamsCache = createSearchParamsCache(searchParams) export const serialize = createSerializer(searchParams); 13
2. ページロード時のsearchParamsと同期をとる clientでのuseQueryStateのsetを初期で行うイメージ export default function Page({ searchParams }: {
searchParams: Record<string, string | string[] | undefined> }) { const searchParamsCache.parse(searchParams) // ... } 14
3. cacheは .all または .get で取得可能 ナビゲーションによってクエリのcacheが更新される const { q,
maxResults } = searchParamsCache.all(); const setQuery = (query: string) => { return serialize("/", { q: query, maxResults }); }; return ( <Link href={setQuery("test-query")}}>Link</Link> ) stateとのリアルタイムな同期は流石にClient Componentが必要 ただしsearchParamsCacheとuseQueryStateとの連携は可能 15
蛇足 Next.jsがソフトナビゲーションにqueryの更新ができる <Form /> コンポーネントを作 っているらしい import Form from 'next/form'
export default function Page() { return ( <Form action="/search"> <input name="query" /> <button type="submit">Submit</button> </Form> ) } Components: <Form> | Next.js 16
良いqueryライフを! 17