yucatio@システムエンジニア

趣味で作ったものいろいろ

date-fnsを使用してカレンダー作成する(その2: React hooksを利用して月を移動する)

前回の記事の続きです。前の月や次の月に遷移できるようにします。Reactバージョン16.8.0から登場したReact hooksを使用します。

★前回の記事

yucatio.hatenablog.com

要件

  • カレンダーを表示したい

最終的にはこちらが出来上がります↓

f:id:yucatio:20191223081351p:plain

デモ : date-fns calendar

仕様

  • デフォルトで今月のカレンダーを表示する
  • 日曜日を行の一番始めにする
  • "次の月"のボタンが押されたら、次の月のカレンダーを表示する
  • "前の月"のボタンが押されたら、前の月のカレンダーを表示する
  • "今月"のボタンが押されたら、今月のカレンダーを表示する

f:id:yucatio:20191223133127p:plain

f:id:yucatio:20191223133113p:plain

f:id:yucatio:20191223133143p:plain

コード

次の月、前の月、今月のボタンを追加したコードです。

import React, { useState }  from 'react'  // useStateを追加
import format from 'date-fns/format'
import getDate from 'date-fns/getDate'
import getDay from 'date-fns/getDay'
import eachDayOfInterval from 'date-fns/eachDayOfInterval'
import endOfWeek from 'date-fns/endOfWeek'
import eachWeekOfInterval from 'date-fns/eachWeekOfInterval'
import addMonths from 'date-fns/addMonths'  // 追加
import subMonths from 'date-fns/subMonths'  // 追加
import startOfMonth from 'date-fns/startOfMonth'
import endOfMonth from 'date-fns/endOfMonth'

const getCalendarArray = date => {
  const sundays = eachWeekOfInterval({
    start: startOfMonth(date),
    end: endOfMonth(date)
  })
  return sundays.map(sunday =>
    eachDayOfInterval({start: sunday, end: endOfWeek(sunday)})
  )
}

function App() {
  const [targetDate, setTargetDate] = useState(new Date())  // 変更
  const calendar = getCalendarArray(targetDate)

  return (
    <div>
      {/* 追加ここから */}
      <div>
        <button onClick={() => setTargetDate(current => subMonths(current, 1))}>前の月</button>
        <button onClick={() => setTargetDate(new Date())}>今月</button>
        <button onClick={() => setTargetDate(current => addMonths(current, 1))}>次の月</button>
      </div>
      {/* 追加ここまで */}

      {format(targetDate, 'y年M月')}
      <table>
        <thead>
          <tr>
            <th>日</th><th>月</th><th>火</th><th>水</th><th>木</th><th>金</th><th>土</th>
          </tr>
        </thead>
        <tbody>
          {calendar.map((weekRow, rowNum) => (
            <tr key={rowNum}>
              {weekRow.map(date => (
                <td key={getDay(date)}>{getDate(date)}</td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}

export default App

コードの解説

React hooksを使用します。表示する月に属する日付をtargetDateに格納します。初期値はnew Date() です。更新用の関数にはsetTargetDateという名前をつけます。

const [targetDate, setTargetDate] = useState(new Date()); 

次に、前の月、今月、次の月のボタンを表示します。

      <div>
        <button>前の月</button>
        <button>今月</button>
        <button>次の月</button>
      </div>

実行結果です↓

f:id:yucatio:20191223121610p:plain

ボタンが押された時のアクションを追加します。 "次の月"が押されたときは、targetDateに1ヶ月足します。 "前の月"が押されたときは、targetDateから1ヶ月引きます。 "今月"が押されたときは、現在時刻をtargetDateに設定します。

      <div>
        <button onClick={() => setTargetDate(subMonths(targetDate, 1))}>前の月</button>
        <button onClick={() => setTargetDate(new Date())}>今月</button>
        <button onClick={() => setTargetDate(addMonths(targetDate, 1))}>次の月</button>
      </div>

動作確認です。

"前の月"を押したときに次の月に遷移します。

f:id:yucatio:20191223133113p:plain

"次の月"を押したときに次の月に遷移します。

f:id:yucatio:20191223133127p:plain

"今月"を押した時に、今月のカレンダーが表示されます↓

f:id:yucatio:20191223133143p:plain

以上でReact hooksを利用して月を移動することができました。

ソースコード

ここまでのソースコードです。

GitHub - yucatio/date-fns-calendar at 87835db6805769c8d10cf56aebdc0e06e06638bd

環境

  • npm: 6.12.1
  • react: 16.12.0
  • date-fns: 2.8.1

次回の記事

次回はMaterial-UIを利用して見た目を整えます。

yucatio.hatenablog.com