【Next.js】cookies 関数を使って Cookie を操作する

2024/10/22に公開

はじめに

業務において Next.js のcookies関数を使用して Cookie を作成・取得するという機会があったので、実装を行うにあたって参考にした公式ドキュメントをもとに、Next.js での Cookie の扱い方をまとめました。

参考にしたドキュメントはこちら👇

https://nextjs.org/docs/app/api-reference/functions/cookies

Cookie とはサーバーからブラウザに送られる小さな文字列データです。ブラウザは Cookie を保存・新規作成・変更などを行うことができます。さらにはその後リクエストされたときに同じサーバーに送り返したりもできます。

Cookie は Web アプリにおいて次の3つの用途で使われることが多いです。

1. セッション管理:ユーザーのログイン状態など
2. パーソナライズ:表示言語や UI テーマなど
3. トラッキング:ユーザーの行動記録および分析

https://developer.mozilla.org/ja/docs/Web/HTTP/Cookies

Next.js の cookies 関数

Next.js では Cookie の作成・取得・変更・削除を行うことができるcookies関数が提供されています。
cookies関数を利用すると、サーバーコンポーネントから HTTP リクエストの Cookie を読みとったり、Server Actions や Route API で HTTP レスポンスに Cookie を書き込むことができます。

cookies関数は返り値を事前に知ることができない動的関数です。つまり、layoutpageでこの関数を利用すると、そのページはリクエスト時に動的にレンダリングされます。あくまでサーバーでの処理を行うための関数であり、クライアントサイドでの処理には基本的には使えません。クライアント側で Cookie を扱う場合、以下のようなライブラリが提供されています。

https://github.com/js-cookie/js-cookie

cookies関数のメソッド

cookies().get(name)

Cookie の名前を引数に取り、名前と値のセットのオブジェクトを返します。name に対応する Cookie が存在しない場合は、undefinedを返します。
もし 名前に対応する Cookie が複数存在する場合は、最初に見つかったものを返します。

app/page.tsx
import { cookies } from 'next/headers'

export default function Page() {
  const cookieStore = cookies()
  const theme = cookieStore.get('theme')
  console.log(theme) // { name: 'theme', value: 'dark' }

  return ...
}

cookies().getAll(name)

cookies.get()に似ていますが、get()と異なるのは引数に指定されたnameと一致する全ての名前と値のオブジェクトを返すことです。もし名前が指定されない場合は、名前に限らず全ての Cookie を返します。

app/page.tsx
import { cookies } from 'next/headers'

export default function Page() {
  const cookieStore = cookies()

  // 引数が指定されていないので全ての Cookie が走査される
  return cookieStore.getAll().map((cookie) => (
    <div key={cookie.name}>
      <p>Name: {cookie.name}</p>
      <p>Value: {cookie.value}</p>
    </div>
  ))
}

cookies().has(name)

nameを引数に取り、その名前の Cookie が存在するかどうかをbooleanで返します。

app/page.tsx
import { cookies } from 'next/headers'

export default function Page() {
  const cookieStore = cookies()
  const hasCookie = cookieStore.has('theme')
  console.log(hasCookie) // true or false

  return '...'
}

cookies().set(name, value, options)

名前と値とオプションを引数に取り、送信リクエストの Cookie を設定します。
HTTP ではストリーミングが始まった後に Cookie をセットすることはできません。したがって、set()Server ComponentsRoute Handler でのみ利用できます。どちらにしろサーバー側のエンドポイントに対してリクエストを送る形で Cookie をセットしなければいけないということですね。

以下のコードは Server Actions で Cookie を設定する例です。

app/actinos.js
'use server'
import { cookies } from 'next/headers'

async function create(data) {
  cookies().set('name', 'lee')
  // or
  cookies().set('name', 'lee', { secure: true })
  // or
  cookies().set({
    name: 'name',
    value: 'lee',
    httpOnly: true,
    path: '/',
  })
}

こちらの記事ではちょうど Cookie を例に2つの方法の説明やどちらを選べばいいのかを詳細に説明されているので、気になる方はぜひ目を通してみてください。

https://zenn.dev/coconala/articles/82a805fa39e76b

Cookie の削除にはいくつかの方法があります。ただし、いずれにしても set()と同じように Server Actions もしくは Route Handler で行う必要があります。

cookies().delete(name)

nameを引数に渡して明示的に削除する方法です。

app/actions.ts
'use server'
 
import { cookies } from 'next/headers'
 
async function delete(data) {
  cookies().delete('name')
}

cookies().set(name, '')

別の方法として、同じ名前で空文字の値を持つ Cookie を作成することで既存の Cookie の値を上書きすることもできます。

app/actions.ts
'use server'
 
import { cookies } from 'next/headers'
 
async function delete(data) {
  cookies().set('name', '')
}

他にも以下のようなやり方もありますが、登場頻度は上の2つほどはないかなと思います。

  • cookies().set(name, value, { maxAge: 0 })maxAgeプロパティの値を0にすることで即座に削除する方法
  • cookies().set(name, value, { expires: timestamp })expiresプロパティの値をどの時点でもいいので過去に設定することで削除する方法

おわりに

最後まで読んでいただきありがとうございます。
Cookie の基本的な概念や Next.js のcookies関数のAPIは意外とシンプルですが、これを実装にまで落とし込むとなるとつまづくところもあり、まだまだコードを書く量が圧倒的に足りていないと感じました。Cookie を始め Server Action や RCS については @Leerob など Vercel の内部のエンジニアが YouTube で発信してくれているのでそれらを参考にしつつ、これからも学習を続けていきたいです。

https://youtu.be/DJvM2lSPn6w?si=PMo7AfJXFg-ZGTDm

Discussion