Next.js と TypeScript で、ブックマーク機能を実装

TwitterFacebookHatena

TL;DR

今日は Next.js と TypeScript を用いて、Web Storage API を使ったブックマーク機能の実装方法について深堀りしていきます。

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

Web Storage API とは?

Web Storage API は、ウェブブラウザ上でキーと値のペアを保存するための API です。ブラウザ上でデータを保存したい場合、一般的には 2 つの方法、"localStorage" と "sessionStorage" があります。どちらも同じ Web Storage API を使用しますが、その振る舞いには微妙な違いがあります。

  • localStorage: こちらはウェブページのセッション間(ブラウザを閉じて再開するなど)でもデータを保持します。つまり、永続的なデータストレージとなります。
  • sessionStorage: こちらは現在開いているページのセッション中だけデータを保持します。ページやブラウザを閉じるとデータは消えてしまいます。

これらの特性を利用して、ブックマーク機能のようなユーザー固有のデータを保存する場合によく用いられます。

簡単な localStorage の使用例を見てみましょう。

// データの保存
localStorage.setItem('myKey', 'myValue')

// データの取得
const data = localStorage.getItem('myKey') // myValue

Next.js で、Web Storage API でブックマーク機能を実装

では、Next.js の環境でブックマーク機能を実装してみましょう。

ファイル名: Bookmark.tsx

import { useState, useEffect } from 'react'

type Props = {
  id: string
}

const Bookmark = ({ id }: Props) => {
  const [bookmarked, setBookmarked] = useState(false)

  useEffect(() => {
    setBookmarked(Boolean(localStorage.getItem(id)))
  }, [id])

  const toggleBookmark = () => {
    if (bookmarked) {
      localStorage.removeItem(id)
    } else {
      localStorage.setItem(id, 'bookmarked')
    }
    setBookmarked(!bookmarked)
  }

  return <button onClick={toggleBookmark}>{bookmarked ? 'Remove bookmark' : 'Add bookmark'}</button>
}

ここでは、ブックマークを追加・削除するための Bookmark コンポーネントを作成しました。コンポーネントはブックマークする項目の id を受け取ります。

初期化時、useEffect により localStorage をチェックし、該当 id のブックマークが存在するか確認します。存在すれば bookmarkedtrue に設定します。

toggleBookmark 関数は、ボタンがクリックされた時に呼び出され、ブックマークの追加と削除を行います。

Web Storage API でブックマーク機能を実装

今度は、より発展的な例を見てみましょう。

ファイル名: BookmarkList.tsx

import { useState, useEffect } from 'react'
import Bookmark from './Bookmark'

type Post = {
  id: string
  title: string
}

type Props = {
  posts: Post[]
}

const BookmarkList = ({ posts }: Props) => {
  const [bookmarks, setBookmarks] = useState<string[]>([])

  useEffect(() => {
    const storedBookmarks = Object.keys(localStorage)
    setBookmarks(storedBookmarks)
  }, [])

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>
          <h2>{post.title}</h2>
          <Bookmark id={post.id} />
        </li>
      ))}
    </ul>
  )
}

ここでは、投稿のリストを受け取り、それぞれの投稿にブックマークボタンを追加する BookmarkList コンポーネントを作成しました。ページロード時には、localStorage からすべてのブックマークを取得し、それをbookmarksステートに設定します。

Emotion で実装

最後に、Emotion を使ってブックマークボタンをスタイリングしてみましょう。

ファイル名: Bookmark.tsx

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

type Props = {
  id: string
}

const buttonStyles = css`
  background-color: transparent;
  border: none;
  cursor: pointer;
  padding: 10px;
  color: #333;
  font-size: 16px;
`

const Bookmark = ({ id }: Props) => {
  const [bookmarked, setBookmarked] = useState(false)

  useEffect(() => {
    setBook

    marked(Boolean(localStorage.getItem(id)))
  }, [id])

  const toggleBookmark = () => {
    if (bookmarked) {
      localStorage.removeItem(id)
    } else {
      localStorage.setItem(id, 'bookmarked')
    }
    setBookmarked(!bookmarked)
  }

  return (
    <button css={buttonStyles} onClick={toggleBookmark}>
      {bookmarked ? 'Remove bookmark' : 'Add bookmark'}
    </button>
  )
}

ここでは、Emotion の css 関数を使ってスタイルを定義し、そのスタイルをボタンに適用しています。

以上の例からわかるように、Web Storage API はブラウザにデータを保存し、ページを離れてもデータが残るようにする機能です。Next.js と TypeScript を使うと、この API を使ってユーザーのブックマークを管理する機能を簡単に実装できます。

Next.js と TypeScript で、ブックマーク機能を実装