Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Next.jsでクエリパラメータを楽に扱おう nuqsを紹介!
Search
imaimai17468
September 06, 2024
2.2k
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
290
MVP先行の探索型DocDD
imaimai17468
1
200
コーディングチェックの自動化がしたい!
imaimai17468
4
1.2k
型パズルを好きになるために、競プロを型システムだけで解いてみることにした
imaimai17468
6
820
フロントエンド設計の所感 1年目
imaimai17468
0
110
Silk Weave -未来研究大会発表資料-
imaimai17468
1
72
TailwindCSSで学ぶ技術批判の気をつけ方
imaimai17468
8
7.1k
Next.js+yjs+BlockNoteでNotionライクな最高の共同編集エディタを作ろう
imaimai17468
0
3.3k
BlockNoteを布教するぜ
imaimai17468
0
85
Featured
See All Featured
30 Presentation Tips
portentint
PRO
1
390
エンジニアに許された特別な時間の終わり
watany
109
250k
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
3
4.3k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
300
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
280
Rails Girls Zürich Keynote
gr2m
96
14k
[RailsConf 2023] Rails as a piece of cake
palkan
59
7k
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.6k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
610
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
450
Rebuilding a faster, lazier Slack
samanthasiow
85
9.6k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
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