Next.jsでcookieを扱うのは大変
Next.jsなどのサーバーサイドレンダリング(以下SSR)をしているフレームワークでcookieを扱うのは面倒くさいですよね。
その理由の一つとして、同じコードでもSSRの場合とクライアントでレンダリングしている場合で挙動が違うということがあります。
例をお見せしましょう
クライアントでレンダリングしている場合
console.log(document.cookie); // accessToken=test1234;
SSRの場合
console.log(document.cookie); // ReferenceError: document is not defined
原因
クライアントサイド(ブラウザ)でレンダリングしている時は、ブラウザに保存されているcookieにアクセスできるが,
SSRの時はブラウザに保存されているcookieにアクセスできません。
SSRの時にcookieを扱うには
SSRでcookieの情報はここに入っています
const TestPage: NextPage<Props> = (props) => {
return <div>test</div>
}
TestPage.getInitialProps(ctx) {
// ここ
console.log(ctx.req.headers.cookie) // accessToken=test1234;
return {};
}
同じライブラリをクライアントとSSRで共有していたりすると、条件分岐などが大変ですね
そんな時に nookies を使います
https://www.npmjs.com/package/nookies
使い方
以下の例で示すようにクライアントサイドの場合ctxを渡さずに、SSRならctxを渡せば、cookieをオブジェクトに整形して返してくれます。
import { parseCookies } from 'nookies';
import { NextPageContext } from 'next';
export function printCookie(ctx?: NextPageContext) {
const cookie = parseCookies(ctx);
console.log(cookie) // { accessToken: 'test1234' }
}
また、cookieの追加もクライアントとSSR分け隔てなく行ってくれます
import { setCookie, destroyCookie } from 'nookies';
import { NextPageContext } from 'next';
export function setCookie(ctx?: NextPageContext, token: string) {
setCookie(ctx, 'accessToken', token, {
maxAge: 30 * 24 * 60 * 60,
});
}
// ついでにcookie削除(動作確認してません)
export function destroyCookie(ctx?: NextPageContext) {
destroyCookie(ctx, 'accessToken')
}
ライブラリを読んでみた(箇条書きです!)
const isBrowser = () => typeof window !== 'undefined' // 今の環境がSSRかクライアントサイドレンダリングか調べてるらしいです
.
.
if (ctx && ctx.req && ctx.req.headers && ctx.req.headers.cookie) {
return cookie.parse(ctx.req.headers.cookie as string, options) // SSRだったらctx.req.headers.cookieに入っているcookieをparseして返却
}
.
.
if (isBrowser()) {
return cookie.parse(document.cookie, options) //クライアントだったらdocument.cookieにあるcookieをparseして返却
}
.
.
ctx.res.setHeader('Set-Cookie', cookiesToSet) // SSRならレスポンスヘッダーにcookieをセットする
.
.
if (isBrowser()) { |
document.cookie = cookie.serialize(name, value, options) // クライアントならクッキーをセット
}
まとめ
以上です。いかがでしたでしょうか?
参考になりましたら幸いです。