Next.js と TypeScript で、Web Storage API を使う

TwitterFacebookHatena

TL;DR

このページでは、Web Storage API の実装方法について解説しますね。Next.js と TypeScript を使用し、データの保存や読み出しを行うための具体的な手順とコードをご紹介します。

開発環境 バージョン
Next.js 13.4.4
TypeScript 5.0.4
Emotion 11.11.0
React 18.2.0

Web Storage API とは?

Web Storage API は、ブラウザによるデータの保存を可能にする機能の一つです。キーと値の組み合わせによってデータを保存し、そのデータを後で取り出すことができます。主に、セッションストレージとローカルストレージの 2 つの種類があります。

セッションストレージは、ブラウザのタブが閉じられるとそのデータが消去されます。一方で、ローカルストレージはブラウザを閉じてもデータが残ります。これらの違いを理解し、目的に応じて適切なストレージを選ぶことが大切です。

基本的な使い方は次の通りです。まずデータを保存するには、setItemメソッドを使います。setItemは 2 つの引数を取ります。1 つ目の引数はキー、2 つ目の引数は値です。

localStorage.setItem('key', 'value')

データを取得するにはgetItemメソッドを使います。このメソッドは 1 つの引数、つまり取得したいデータのキーを指定します。

const value = localStorage.getItem('key')

また、データを削除するにはremoveItemメソッドを使います。削除するデータのキーを引数に渡します。

localStorage.removeItem('key')

どのようなときに使うのか?

Web Storage API を利用することで、以下のような機能を実装できます。

ダークモードとライトモードの切り替え

ユーザーがサイトの見た目をダークモードとライトモードの間で切り替えられるようにします。この設定はローカルストレージに保存され、次回訪問時もユーザーの選択が反映されます。

ブックマークの保存

ユーザーが特定のコンテンツをブックマークできるようにします。これらのブックマークはローカルストレージに保存され、ユーザーが後で簡単にアクセスできます。

最近閲覧したアイテムのリスト

商品や記事など、ユーザーが最近閲覧したアイテムのリストを提供します。このリストはローカルストレージに保存され、ユーザーが後でアクセスできます。

フォームの自動完成

ユーザーが以前に入力したフォームの情報を保存しておくことで、同じフォームを再度訪れたときに自動的に情報を入力する機能を提供します。

ゲームのスコアや進行状況の保存

ブラウザゲームでプレイヤーのスコアや進行状況をローカルストレージに保存し、ゲームを再開するときにその情報を復元します。

オフライン時のデータキャッシュ

オフライン時でも特定のデータを表示できるように、一部の情報をローカルストレージに保存します。

※ Web Storage API の利用には注意が必要です。これは、大量のデータを保存するためのものではなく、また、敏感な情報(パスワードや個人情報など)を保存するためのものでもありません。そのため、データの量や種類に注意しながら適切に使用することが重要です。

保存期間

Web Storage API には 2 つの主要なストレージタイプがあり、それぞれが異なる保存期間を持っています。

セッションストレージ(sessionStorage)

このタイプのストレージは、ブラウザのタブまたはウィンドウが閉じられたときに自動的にクリアされます。つまり、セッションストレージに保存されたデータは、ブラウザを閉じると失われます。同じブラウザでも、新しいタブやウィンドウを開いた場合、それぞれが独自のセッションストレージを持ちます。

ローカルストレージ(localStorage)

このタイプのストレージは永続的で、ブラウザを閉じてもデータは保持されます。データは手動でクリアしない限り、無期限に保持されます。また、同じブラウザの異なるタブやウィンドウ間で共有されます。

保存期間が必要な場合や、セキュリティ上の理由で自動的にデータをクリアしたい場合は、セッションストレージを利用します。一方、永続的にデータを保存したい場合や、ブラウザを閉じてもデータを保持したい場合は、ローカルストレージを利用します。ただし、どちらのストレージタイプも、ユーザー自身がブラウザの設定でデータをいつでも削除できることを覚えておくことが重要です。

メソッド

ローカルストレージを操作するためには、以下のメソッドが主に利用されます。

  • setItem(key, value): ローカルストレージに新しいデータを保存します。keyはデータの名前を表し、valueは保存するデータそのものです。valueは文字列である必要があるため、オブジェクトや配列を保存する場合は、JSON.stringify()を用いて文字列化する必要があります。

  • getItem(key): ローカルストレージからデータを取得します。引数のkeyに対応するデータが存在すればそのデータが文字列として返されます。なお、setItem()で保存した際に文字列化したオブジェクトや配列を取得する場合は、JSON.parse()を用いて元のデータ型に戻す必要があります。

  • removeItem(key): ローカルストレージから指定したkeyのデータを削除します。

  • clear(): ローカルストレージの全てのデータを削除します。

これらのメソッドを使うことで、ブラウザのローカルストレージを操作し、データの保存、取得、削除を行うことができます。

ストレージイベント

ストレージイベントについてお話ししますね。このイベントは、localStorage または sessionStorage のデータが変更されるたびに発生します。一つのタブやウィンドウでデータが変更されると、他の全てのタブやウィンドウでこのイベントが発生します。これにより、同一ブラウザ内の異なるタブやウィンドウ間でデータを同期することができます。

ただし、注意すべき点として、同一のページでデータが変更された場合、そのページ自体ではストレージイベントは発生しません。つまり、イベントは常に他のページからの変更を監視するために存在します。

以下に、ストレージイベントがどのように機能するかを示す基本的な例を見てみましょう。この例では、一つのタブでデータが変更されたときに他のタブがそれを検知し、反応します。

// 他のタブでの変更を監視する
window.addEventListener('storage', function (event) {
  if (event.key == 'myData') {
    alert('データが変更されました: ' + event.newValue)
  }
})

// データを変更する
localStorage.setItem('myData', '新しいデータ')

このように、ストレージイベントを使うと、ブラウザのタブ間でデータをリアルタイムに同期することができます。例えば、ユーザーがブックマークを追加または削除したとき、開いている他の全てのタブでその変更を反映することが可能になります。

Next.js で、Web Storage API を実装

では、Next.js と TypeScript を使って、具体的なソースコードを書いてみましょう。

まずは、次のようなファイルを作成します:components/StorageExample.tsx

import { useEffect, useState } from 'react'

type Props = {
  initialKey: string
  initialValue: string
}

const StorageExample = ({ initialKey, initialValue }: Props) => {
  const [storageValue, setStorageValue] = useState<string | null>(null)

  useEffect(() => {
    localStorage.setItem(initialKey, initialValue)
    const storedValue = localStorage.getItem(initialKey)
    setStorageValue(storedValue)
  }, [initialKey, initialValue])

  return <div>Stored Value: {storageValue}</div>
}

export default StorageExample

このコンポーネントでは、initialKeyinitialValueという 2 つのプロップスを受け取り、それをローカルストレージに保存します。保存した値はその後取得され、storageValueというステートに保存されます。そして、その値は画面上に表示されます。

Web Storage API を活用

では、次により具体的な実装を見てみましょう。例えば、ユーザーがサイトにログインした際の情報をローカルストレージに保存し、その情報を元にページの表示を制御するような機能を考えてみます。

次のようなファイルを作成します:components/Login.tsx

import { useEffect, useState } from 'react'

type User = {
  name: string
  token: string
}

type Props = {
  user: User
}

const Login = ({ user }: Props) => {
  const [isLogged, setIsLogged] = useState<boolean>(false)

  useEffect(() => {
    localStorage.setItem('user', JSON.stringify(user))
    const storedUser = JSON.parse(localStorage.getItem('user') || '')
    if (storedUser && storedUser.token) {
      setIsLogged(true)
    }
  }, [user])

  return <div>Welcome {isLogged ? user.name : 'Guest'}</div>
}

export default Login

Emotion で実装

では最後に、スタイルの適用について見てみましょう。ここでは、Emotion を使用してスタイルを適用します。例えば、ログインしているユーザーの名前を強調表示することを考えてみます。

components/StyledLogin.tsx というファイルを作成します。

/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
import { useEffect, useState } from 'react'

type User = {
  name: string
  token: string
}

type Props = {
  user: User
}

const loginStyle = css`
  font-size: 1.5em;
  font-weight: bold;
  color: blue;
`

const Login = ({ user }: Props) => {
  const [isLogged, setIsLogged] = useState<boolean>(false)

  useEffect(() => {
    localStorage.setItem('user', JSON.stringify(user))
    const storedUser = JSON.parse(localStorage.getItem('user') || '')
    if (storedUser && storedUser.token) {
      setIsLogged(true)
    }
  }, [user])

  return <div css={isLogged ? loginStyle : undefined}>Welcome {isLogged ? user.name : 'Guest'}</div>
}

export default Login

このコードでは、ログインしているユーザーの名前に対して、loginStyleというスタイルを適用しています。loginStyleでは、フォントの大きさ、重さ、色を設定しており、これによりログインユーザーの名前が強調表示されます。

以上のように、Next.js と TypeScript を使用することで、Web Storage API を用いた具体的な機能を実装することが可能になります。そして、Emotion を利用することで、その機能に対して動的にスタイルを適用することもできます。

Next.js と TypeScript で、Web Storage API を使う