Next.js と TypeScript で、slice() メソッドを使いページネーションを作る

TwitterFacebookHatena

TL;DR

このページでは、slice() メソッドを使ったページネーションの実装方法について詳しく解説しますね。一言で言えば slice() とは、配列や文字列から特定の範囲を切り出すためのメソッドです。

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

slice() メソッドとは?

そもそも slice() メソッドとは何でしょうか。slice() メソッドは、配列や文字列から特定の範囲を取り出すためのメソッドです。このメソッドを使うことで、新たな配列や文字列を作成することができます。

slice() メソッドは、元の配列や文字列を変更せずに、新たな配列や文字列を作成するという特性を持つため、非破壊的な操作を行いたい場合に非常に便利です。

基本的な使い方は以下のようになります。

const array = [1, 2, 3, 4, 5]
const newArray = array.slice(1, 3)
console.log(newArray) // Output: [2, 3]

このコードでは、配列 array の 1 番目のインデックスから 3 番目のインデックスまでの範囲を slice() メソッドを使って切り出しています。このとき、新たに作成された newArray[2, 3] という値を持ちます。

また、slice() メソッドは文字列にも利用できます。以下にその例を示します。

const str = 'Hello, World!'
const newStr = str.slice(0, 5)
console.log(newStr) // Output: "Hello"

この例では、文字列 str の 0 番目から 5 番目までの範囲を slice() メソッドで切り出しています。その結果、newStr"Hello" という値を持ちます。

ページネーションの実装

ページネーションとは、データを分割して表示する方法の一つで、主に大量のデータを一度に表示することが難しい場合に使用されます。ウェブページやアプリケーションでは、一覧表示をする際に多くの場合、ページネーションが利用されます。

JavaScript のslice()メソッドはこのページネーションを実装する際に非常に役立ちます。slice()メソッドを使用することで、配列から特定の範囲の要素を取り出すことができます。この機能を利用して、表示するデータの範囲を動的に変更することで、ページネーションを実現できます。

例えば、以下のようなソースコードでデータの一部を切り出して表示することが可能です。

const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const perPage = 5
const currentPage = 1

const start = perPage * (currentPage - 1)
const end = start + perPage

const displayData = data.slice(start, end)

console.log(displayData) // [1, 2, 3, 4, 5]

ここで、perPage は 1 ページあたりに表示するデータの数、currentPage は現在のページ番号を表します。startendslice() メソッドの引数として使用され、データのどの範囲を切り出すかを指定します。

Next.js で、ページネーションを実装

それでは、具体的に Next.js のプロジェクトでどのようにページネーションを実装するか見てみましょう。以下のソースコードは、pages/index.tsx となります。

import { useState } from 'react'

type DataProps = {
  data: number[]
}

const perPage = 5

const IndexPage = () => {
  const allData = Array.from({ length: 50 }, (_, i) => i + 1)
  const [currentPage, setCurrentPage] = useState(1)

  const handlePageChange = (page: number) => {
    setCurrentPage(page)
  }

  const start = perPage * (currentPage - 1)
  const end = start + perPage
  const data = allData.slice(start, end)

  return (
    <div>
      <DataList data={data} />
      <button onClick={() => handlePageChange(currentPage - 1)} disabled={currentPage === 1}>
        Prev
      </button>
      <button onClick={() => handlePageChange(currentPage + 1)} disabled={currentPage === Math.ceil(allData.length / perPage)}>
        Next
      </button>
    </div>
  )
}

const DataList = ({ data }: DataProps) => {
  return (
    <ul>
      {data.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  )
}

export default IndexPage

このコードでは、まず 1 から 50 までの数字を含む配列allDataを作成しています。そして、現在のページ番号を保持するための state currentPageを設定しています。そして、handlePageChange関数を定義して、ページを切り替える際に使用します。

そして、表示するデータの範囲をslice()メソッドで切り出し、DataListコンポーネントに渡しています。最後に、ページ切り替えのためのボタンを配置して、それぞれのボタンが押されたときにhandlePageChange関数を呼び出して、ページを切り替えるようにしています。

ここで、ページネーションを構成する主要な部分は以下の部分です。

  1. slice()を使用して、現在のページに対応するデータを切り出す部分
  2. ページを切り替えるためのボタンとその処理

この 2 つの要素があれば、基本的なページネーションの機能を実装することが可能です。

複雑なデータ構造でのページネーションの実装

次に、より複雑なデータ構造でページネーションを実装する例を見てみましょう。例えば、オブジェクトの配列が与えられて、その配列をページネーションする場合を考えてみます。

type Product = {
  id: number
  name: string
}

type DataProps = {
  data: Product[]
}

const perPage = 5

const IndexPage = () => {
  const allData: Product[] = Array.from({ length: 50 }, (_, i) => ({ id: i + 1, name: `Product ${i + 1}` }))
  // idが1から50までの、名前がそれぞれ"Product 1"から"Product 50"までの商品を作成し、それらを配列にしてallDataという変数に代入している
  const [currentPage, setCurrentPage] = useState(1)

  const handlePageChange = (page: number) => {
    setCurrentPage(page)
  }

  const start = perPage * (currentPage - 1)
  const end = start + perPage
  const data = allData.slice(start, end)

  return (
    <div>
      <DataList data={data} />
      <button onClick={() => handlePageChange(currentPage - 1)} disabled={currentPage === 1}>
        Prev
      </button>
      <button onClick={() => handlePageChange(currentPage + 1)} disabled={currentPage === Math.ceil(allData.length / perPage)}>
        Next
      </button>
    </div>
  )
}

const DataList = ({ data }: DataProps) => {
  return (
    <ul>
      {data.map((item, index) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  )
}

export default IndexPage

このコードでは、Productという型を定義し、その型の配列をページネーションします。それぞれの商品は一意のidnameを持っています。これらのデータは、DataListコンポーネントで表示されます。

そして、次のコードを見てみましょう。

const allData: Product[] = Array.from(
  // 50 個の空の要素を持つ配列を作成
  { length: 50 },
  (_, i) => ({
    // 新たな配列の各要素に対して実行する関数を定義
    id: i + 1,
    name: `Product ${i + 1}`,
  })
)

この行のコードは、「商品リスト」を作成している部分です。商品は、それぞれ「id」と「名前(name)」を持つと定義しています。そして、その「商品」を 50 個作るというのが、このコードの目的です。

それでは、このコードの各部分を一つずつ見てみましょう。

  • Array.from({ length: 50 }, ...):

    これは、長さが 50 の配列を作成する部分です。Array.fromは配列を作成する関数で、{ length: 50 }とすることで、50 個の空の要素を持つ配列を作成します。

  • (_, i) => ({ id: i + 1, name: Product ${i + 1} }):

    これは、上で作成した空の配列の各要素に対して実行する関数を指定しています。ここで、_は配列の要素(この場合はundefined)を、iはその要素のインデックス(0 から 49 まで)を表します。そして、この関数は{ id: i + 1, name: Product ${i + 1} }というオブジェクトを返します。つまり、インデックスに 1 を足した値を id として、その id を含む名前を商品名とする商品を作成しています。

つまり、このコードの全体を見ると、「id が 1 から 50 までの、名前がそれぞれ"Product 1"から"Product 50"までの商品を作成し、それらを配列にしてallDataという変数に代入している」ということになります。これで、後のページネーションのためのデータが準備できました。

Next.js で、slice() メソッドを実装

他のケースとして、Next.js と TypeScript を使って slice() メソッドを活用する例を見てみましょう。以下のソースコードは、pages/index.tsx となります。

import { useState } from 'react'

type DataProps = {
  data: number[]
}

const IndexPage = () => {
  const [data, setData] = useState<number[]>([1, 2, 3, 4, 5])

  const handleSlice = () => {
    const newData = data.slice(1, 4)
    setData(newData)
  }

  return (
    <div>
      <button onClick={handleSlice}>Slice data</button>
      <DataList data={data} />
    </div>
  )
}

const DataList = ({ data }: DataProps) => (
  <ul>
    {data.map((item, index) => (
      <li key={index}>{item}</li>
    ))}
  </ul>
)

export default IndexPage

このコードでは、slice() メソッドを使って配列 data の一部を取り出し、その結果を新たな data としてセットしています。具体的には、handleSlice 関数で data.slice(1, 4) を呼び出し、その結果を setData(newData)data にセットしています。この操作を行うことで、元の配列 data[2, 3, 4] という新たな配列になります。

また、DataList コンポーネントで配列 data を受け取り、それを元にリストを描画しています。これにより、slice() メソッドを使った操作結果をリアルタイムに画面上に表示することができます。

slice() メソッドの応用

さらに、slice() メソッドは応用的な使い方もできます。例えば、ある文字列から特定の文字を取り出して新たな文字列を作る、といった操作が可能です。以下にその例を示します。

type NameProps = {
  name: string
}

const NameComponent = ({ name }: NameProps) => {
  const firstName = name.slice(0, name.indexOf(' '))
  const lastName = name.slice(name.indexOf(' ') + 1)

  return (
    <div>
      <p>First name: {firstName}</p>
      <p>Last name: {lastName}</p>
    </div>
  )
}

このコードでは、フルネームから姓と名を分けて表示する NameComponent コンポーネントを作成しています。ここで、slice() メソッドを用いて、名前の部分と姓の部分を取り出しています。このように、slice() メソッドを活用すれば、文字列や配列を非破壊的に操作することができます。

Next.js と TypeScript で、slice() メソッドを使いページネーションを作る