FullCalendarは、さまざまにカスタマイズしたカレンダーがつくれるオープンソース1のJavaScriptライブラリです。ReactやVueそしてAngularといったフレームワークにも対応しています。とくに、Reactについては、バーチャルDOMノードを生成するという踏み込んだつくり込みです。
とはいえ、まだReactを用いた情報があまりなく、TypeScriptまで含めると、調べるのに苦労するのが現状です。本稿では、ReactとTypeScriptを使って、FullCalendarによるごく簡単なカレンダーのサンプルをつくってみます(図001)。なお、公式サイトのコードサンプルは、多くがクラスを用いています。本稿では、今主流となりつつある関数コンポーネントでコードを書くことにしました。
サンプル001■React + TypeScript + FullCalendar: Basic calendar
React + TypeScriptのひな形作成とFullCalendarのインストール
Reactアプリケーションのひな型は、Create React Appを使うのが簡単です(「Create React App 入門 01: 3×3マスのゲーム盤をつくる」01「Reactアプリケーションのひな形をつくる」)。コマンドのオプションに--template typescript
を加えれば、プロジェクトにTypeScriptの設定が含まれます(プロジェクト名はreact-typescript-fullcalendar
としました)。
npx create-react-app react-typescript-fullcalendar --template typescript
つぎに、プロジェクトのディレクトリ(react-typescript-fullcalendar
)に切り替えて、FullCalendarのインストールです。カレンダーのビューに使うプラグインのdaygrid
も加えてください。
npm install --save @fullcalendar/react @fullcalendar/daygrid
カレンダーを表示する
FullCalendarのimport
は、FullCalendar
を先に、プラグインのdayGridPlugin
はあとから読み込んでください。FullCalendar
コンポーネントのplugins
にプラグインを配列要素として加えます。initialView
は、標準的な月単位のカレンダーdayGridMonth
です(Docs / Month View参照)。
import FullCalendar from "@fullcalendar/react";
import dayGridPlugin from "@fullcalendar/daygrid"; // pluginは、あとから
function App() {
return (
<div>
<FullCalendar plugins={[dayGridPlugin]} initialView="dayGridMonth" />
</div>
);
}
export default App;
これで、月単位のカレンダーが表示されます(図001)。
図001■月単位のカレンダー
日本語表示にする ー localeの設定
FullCalendar
コンポーネントにはlocale
が定められます。値を"ja"
とすれば日本語表示です。
function App() {
return (
<div>
<FullCalendar
locale="ja"
/>
</div>
);
}
ところが、これだけでは完全な日本語表記にはなりません(図002)。
図002■ボタンが日本語表記にならない
公式ドキュメントの「locale」を読んでも、Reactの場合について具体的な説明がありませんでした。試行錯誤してみたところ、つぎのプラグインのインストールがいるようです。
npm install --save @fullcalendar/core
そのうえで、allLocales
をimport
して、locales
に定めたところ、無事日本語表記にできました。
import allLocales from '@fullcalendar/core/locales-all';
function App() {
return (
<div>
<FullCalendar
locales={allLocales}
locale="ja"
/>
</div>
);
}
予定を加える
カレンダーに予定を加えましょう。予定はオブジェクトにして、FullCalendar
コンポーネントのevents
に配列で与えてください。基本的なプロパティとしては、イベント名のtitle
と日時のdate
です。日付のフォーマットは、文字列でYYYY-MM-DDとします。今月の文字列が得られるよう、関数(thisMonth()
)を加えました。
const thisMonth = () => {
const today = new Date();
return `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(
2,
"0"
)}`;
};
function App() {
return (
<div>
<FullCalendar
events={[
{ title: "event 1", date: `${thisMonth()}-01` },
{ title: "event 2", date: `${thisMonth()}-02` },
]}
/>
</div>
);
}
これで、ふたつの予定がカレンダーに加わります(図003)。
図003■ふたつの予定が加わった
クリックした日付を表示する
簡単なインタラクションを加えましょう。クリックしたら、その日付をダイアログで表示することにします。そのためには、プラグインをインストールしなければなりません。
npm install --save @fullcalendar/interaction
import
したinteractionPlugin
は、FullCalendar
コンポーネントのplugins
に加えてください。用いるイベントはdateClick
です。コールバックは、ReactのuseCallback
フックに定めた方がよいでしょう。ハンドラから受け取る引数(arg
)は、プラグインから読み込んだDateClickArg
で型づけします。これで、カレンダーのクリックした日付が、警告ダイアログで示されるはずです。
import { useCallback } from "react";
import interactionPlugin, { DateClickArg } from "@fullcalendar/interaction";
function App() {
const handleDateClick = useCallback((arg: DateClickArg) => {
alert(arg.dateStr);
}, []);
return (
<div>
<FullCalendar
// plugins={[dayGridPlugin]}
plugins={[dayGridPlugin, interactionPlugin]}
dateClick={handleDateClick}
/>
</div>
);
}
書き上がったルートモジュールsrc/App.tsx
の記述全体は、つぎのコード001のとおりです。具体的なコードの動きについては、冒頭のサンプル001をご参照ください。
コード001■ルートモジュール
import { useCallback } from "react";
import FullCalendar from "@fullcalendar/react";
import dayGridPlugin from "@fullcalendar/daygrid";
import allLocales from '@fullcalendar/core/locales-all';
import interactionPlugin, { DateClickArg } from "@fullcalendar/interaction";
const thisMonth = () => {
const today = new Date();
return `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(
2,
"0"
)}`;
};
function App() {
const handleDateClick = useCallback((arg: DateClickArg) => {
alert(arg.dateStr);
}, []);
return (
<div>
<FullCalendar
plugins={[dayGridPlugin, interactionPlugin]}
initialView="dayGridMonth"
locales={allLocales}
locale="ja"
events={[
{ title: "event 1", date: `${thisMonth()}-01` },
{ title: "event 2", date: `${thisMonth()}-02` },
]}
dateClick={handleDateClick}
/>
</div>
);
}
export default App;