Kohei Blog

夫・父親・医療系エンジニア

カレンダーライブラリFullCalendarをReactでカスタマイズして使う

GoogleカレンダーのようなカレンダーUIを簡単に作れるライブラリ「FullCalendar」を実務で使う機会があり、色々とカスタマイズして使ってみたので整理しておく。

「最もポピュラーなJavaScriptカレンダー」

FullCalendar

カレンダーライブラリの選定

カレンダーライブラリを使うにあたり調査しました。候補としては以下の2つ。

どちらも同じようなAPIが用意されており、共通で以下の特徴がありました。

  • TypeScript対応

  • メンテナンスが盛ん

  • 日本語対応

  • ドキュメントが豊富

  • セル内のカスタマイズ自由度→どちらもコンポーネントをPropsとして渡せる

FullCalendarの方が日本語対応が簡単で、開発速度出せそうな感じがしたので採用。

React用のラッパーライブラリを別途インストールする必要があります。

FullCalendarのカスタマイズ

ほぼドキュメントに載っているため、ドキュメント読めばわかるといえばそれまでなのですが、せっかくなのでカスタマイズした内容をメモっておきたいです。

基本のカレンダー

locale、timeZoneを指定するだけで日本対応が可能です。

あとはカレンダーに表示するイベントデータ events と読み込んだプラグインを渡すだけです。

プラグインは、timeGridなど様々なものが用意されていますので用途によって選択します。ここでは、dayGridの通常のカレンダーとインタラクションを与えるプラグインを読み込んでいます。

import FullCalendar from '@fullcalendar/react'
import dayGridPlugin from '@fullcalendar/daygrid'
import interactionPlugin from '@fullcalendar/interaction'

<FullCalendar
  locale='ja'
  timeZone='Asia/Tokyo'
  events={eventData}
  plugins={[dayGridPlugin, interactionPlugin]}
/>

カレンダーに表示するイベントデータ

カレンダーにイベント情報を表示させるには、FullCalendarで定義されているイベントオブジェクトの形式に則る必要があります。

events: [
  {
    title: 'BCH237',
    start: '2019-08-12T10:30:00',
    end: '2019-08-12T11:30:00',
    extendedProps: {
      department: 'BioChemistry'
    },
    description: 'Lecture'
  }
  // more events ...
],

Event Objectとして定義されていて、このオブジェクトの形式に合わせて整形してprops events へ渡します。

プロダクト独自の項目をもたせたい場合は、 extendedProps に格納すれば対応できます。

デフォルトのヘッダーを独自のコンポーネントにカスタマイズする

カレンダーの上部にはデフォルトで「今日」ボタン、翌月、前月ボタンなどのインタラクションが用意されています。

そのままだとイケてないので、独自のコンポーネントでカスタマイズしたい場合が多いかと思います。

CalendarAPIを利用することで、本日の日付に移動したり、翌月に移動させたりすることが可能です。


import FullCalendar from '@fullcalendar/react'

// useRefを使ってインスタンス化する
const calendarRef = useRef<FullCalendar>(null)

// calendarRefのgetApi()でメソッドを呼び出す
const goToNext = () => {
  if (calendarRef.current) {
    calendarRef.current.getApi().next()
    setCurrentDate(calendarRef.current.getApi().getDate())
  }
}

// calendarRefのgetApi()でメソッドを呼び出す
const goToPrev = () => {
  if (calendarRef.current) {
    calendarRef.current.getApi().prev()
    setCurrentDate(calendarRef.current.getApi().getDate())
  }
}

// calendarRefのgetApi()でメソッドを呼び出す
const goToToday = () => {
  if (calendarRef.current) {
    calendarRef.current.getApi().today()
    setCurrentDate(calendarRef.current.getApi().getDate())
  }
}

// ....

// 独自のコンポーネント
<Button onClick={goToToday}>
  今日
</Button>
<Button onClick={goToPrev}>
  前月
</Button>
<Button onClick={goToNext}>
  来月
</Button>
<FullCalendar
  locale='ja'
  timeZone='Asia/Tokyo'
  events={eventData}
  plugins={[dayGridPlugin, interactionPlugin]}
	ref={calendarRef} // RefObjectを渡す
/>

こうすることで、ヘッダー部分のボタン群を独自のコンポーネントへ置き換えることができます。

各種Props

FullCalendarには様々な設定が用意されており、かなり柔軟に対応できるかと思っています。

ただし、一部UIがイケてなかったり、挙動が微妙なものもあるので、その場合は独自コンポーネントに置き換えたりする必要があるかと思っています。

  • eventClick:イベントクリック時にイベント情報を持つEventClickArgを受け取れます。イベント情報の詳細を確認したいときや編集画面を表示させたい時に使えます。

  • fixedWeekCount:これをfalseにしていないと、固定で第5周目まで表示され、第5週目が無い月は、翌月の月初の日付が表示されてしまうので、かなり無駄が多かったです。

  • dayMaxEvents:1日のイベント数の表示上限を設定できます

  • moreLinkContent:上記dayMaxEventsの数を超えた場合、 more +3 といった文字列が表示されます。このコールバック関数に表示したい文字列を渡してカスタマイズできます。

  • dayCellContent:カレンダーの各日の日付部分の表記を変更できます。日本語対応だと「5日」みたいに必ず’日’が入ってくるのが邪魔な場合はここでreplaceしてあげると解決します。

  • eventContent:イベント情報を持つEventContentArgを受け取り、JSXを返す関数を渡せば、カレンダー上に表示させるイベント情報をカスタマイズできます。

  • dayPopoverFormat:morelinkをクリックした時に表示されるPopoverの日付フォーマットを指定できます。

  • headerToolbar:デフォルトのヘッダーツールバーを非表示にできます。ツールバーをカスタマイズしたかったので false に設定しました。

カスタマイズに関して、日本語情報が少ない

この他にも色々とカスタマイズしていますが、日本語情報が少なく、特にReactを使った実装方法が少ないと感じました。

もともとFullCalendarはReact専用ライブラリではなく、JavaScriptライブラリなのでjQueryを使った記事が多かったです。

あとはバージョンの違いでAPIが廃止されてたり、かなり破壊的なバージョンアップが行われている印象を受けました。

ドキュメントを読み溶けるのであれば困らないかもしれませんが、個人的は微妙に苦戦しました。

参考リンク

https://www.mitsue.co.jp/knowledge/blog/frontend/202012/08_0900.html