前回、Next.jsを使ったクライアントサイドでのクエリパラメータを取得する方法を解説しました。
Next.jsでクエリパラメータを遷移先に渡すにはどうすればいいのか? - Qiita
前回使用したuseRouter
フックはクライアントサイドで動きますが、サーバーサイドではエラーになります。そのためサーバーサイドでクエリパラメータを取得するには別の方法が必要です。
なので、今回はサーバーサイドでクエリパラメータを取得する方法を解説します。
サーバーサイドレンダリングでクエリパラメータを取得する方法
まずはサーバーサイドでレンダリングするためgetServerSideProps
の定義が必要です。その際の注意点としては**export
とaync
キーワードをつけること**です。これにより、リクエスト毎にこのページを事前にレンダリングします。
そして、このgetServerSideProps
の中でuseRouter
を使おうとするエラーが発生します。
これはサーバーサイドレンダリングではuseRouter
を使えないためです。クライアントサイドで使う前提になっています。
ここで使えるのがgetServerSideProps
の引数です。通常context
という名前で設定しますが、どんな引数名でも使えるはずです。
このcontext
の中には
- req:HTTPリクエストオブジェクト
- res:HTTPレスポンスオブジェクト
- query:クエリパラメータ
が入っています。この中のquery
の中にクエリパラメータの値が格納されているので、この値を使えばサーバーサイドレンダリングでも使うことができます。
たとえば、次のページを作る際には2つのページが必要になります。
- クエリパラメータを送るページ
- クエリパラメータを受け取るページ
クエリパラメータを受け取るページでは、受け取った値でWebAPIを呼び出してGoogleブックの検索結果を表示しています。
クエリパラメータを送るページ
import { useRouter } from 'next/router';
import {useState} from 'react';
export default function Index() {
const router = useRouter(); //ルーターの取得
const [keyword, setKeyword] = useState(); //検索キーワード
// ボタンをクリックしたときの処理
const clickButton = () => {
//未入力の時
if (!keyword) {
return;
}
router.push({
pathname:"/result", //URL
query: {keyword :keyword} //検索クエリ
});
}
return (
<div style={{textAlign: "center", marginTop: "50px"}}>
{/* 入力項目 */}
<input
type="text"
value={keyword}
onChange={(e) => setKeyword(e.target.value)} /*変更時keywordに値をセット*/
/>
{/* ボタン */}
<button
onClick={clickButton}
disabled={!keyword}> {/*入力項目が未入力の場合、非活性*/}
検索
</button>
</div>
)
}
クエリパラメータを送信するページではuseRouter
フックを使って画面遷移とクエリパラメータの設定を行っています。router.push
メソッドの引数にURLとクエリパラメータをセットしています。
pathname
:URLquery
:クエリパラメータ
注意点としてはクエリパラメータは連想配列で設定します。複数セットする可能性があるためです。
クエリパラメータを受け取るページ
//サーバーサイドレンダリング
export async function getServerSideProps(context) {
//検索キーワード
const keyword = context.query.keyword;
//Googleブックで検索
const response = await fetch (encodeURI(`https://www.googleapis.com/books/v1/volumes?q=${keyword}`));
return {
props: {
bookList: await response.json(), //Googleブックの戻り値
keyword: keyword, //検索キーワード
}
}
}
export default function Result(props) {
//Googleブックの情報を取得
const bookList = props.bookList.items.map(item => item.volumeInfo).map(((item) => {
return {
title : item.title, //タイトル
url : item.infoLink, //URL
}
}));
return (
<div style={{marginLeft: "50px", marginTop: "50px"}}>
<h1>検索キーワード:{props.keyword}</h1>
{/* 検索データの表示 */}
<ul>
{bookList.map((item) =>
<li>
<a href={item.url}>{item.title}</a>
</li>
)}
</ul>
</div>
)
}
一方、遷移先ページではgetServerSideProps
メソッド内でクエリパラメータを取得してgoogleブックで検索した結果をリストで表示しています。
クエリパラメータはcontext.query.keyword
で取得しています。keyword
の部分は遷移元で設定した名前です。
後は、getServerSideProps
の戻り値のprops
にクライアントサイドに渡したい値をセットして表示するだけです。クライアント側でbookList
変数で取得した検索結果を加工して、map関数を使ってリスト表示しています。
まとめ
-
router.push
のpathname
に遷移先URL、query
にクエリパラメータをセットする -
getServerSideProps
を使うことでサーバーサイドレンダリングを利用できる - 引数の
context.query
内に遷移元から送られたクエリパラメータが取得できる