Nuxt.jsでVuetifyカレンダーを使用する際の注意点

# はじめに
Nuxt.jsでVuetifyのv-calendarを使ってみて躓いたところをまとめます。
インストールなどは他の記事があるので割愛します。
# 目次
<!-- タイトルとアンカー名を編集 -->
1. [v-calendarの使い方](#Chapter1)
1. [Vuexで分割したいとき](#Chapter2)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# v-calendarの使い方

```js
<v-calendar
        ref="calendar"
        :events="events"
        :event-color="getEventColor"
        @change="getEvents"
/>
```
カレンダーを表示させるだけなら手間はかかりません。

・ ``events``ではカレンダーに表示する予定が入ります。
基本的には、``name、color、start、end、（timed）``から成り立っています。

``name``・・・予定のタイトル　（文字列）
``color``・・・予定の色を設定
``start``・・・予定の開始時刻（文字列またはUNIX時間）
``end``・・・予定の終了時間（文字列またはUNIX時間）
``timed``・・・終日かどうか(真偽値)

``start、end``の時間が少しややこしいです。
``YYYY-MM-DD hh:mm``形式だと文字列で問題ないですが、カレンダーを週表示や日表示にする際はUNIX時間をおすすめします。``YYYY-MM-DD hh:mm``方式だと予定に対する処理に苦戦します。デフォルトの処理はUNIX時間をもとに実行されるため、カレンダーやイベントを表示する以外の処理を行いたい方はUNIX時間でイベント設定することを推奨します。
ちなみに``:eventColorや、@change``はなくても問題ありません。イベントと、イベントの色をランダムで配置するための関数です。
![スクリーンショット 2022-03-18 11.51.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641519/fa86265e-62ac-e34d-1989-fa30cf0b4670.png)

### 週表示
週表示にするだけなら簡単です。
``type="week"``を追加します。

```js
        <v-calendar
          ref="calendar"
          :now="today"
          :value="today"
          :events="events"
          color="primary"
       ++ type="week"
```

![スクリーンショット 2022-03-18 11.57.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641519/8da2e5f8-70fe-77e1-e386-e25f70780bb3.png)
このほかにも、``day``、``4day``とあり、1日のみ表示、4日表示などのカスタマイズができます。


### その他のオプション
Vuetifyのカレンダーにはオプションがたくさん用意されています。ページ数もかなり多く、全てを把握するのは大変です。
しかし、その分カスタマイズの幅が広くて面白いです。
オプションを組み合わせることでドラッグ&ドロップなどの機能も追加できます。
![ドラッグ&ドロップ.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641519/49f9bd72-743c-f91b-9f97-87240a215ab7.gif)



### 日本語に対応させる
デフォルトでは英語になっていますが、日本語に対応させたい場合もあります。
日本語に変更するときは``locale="ja-jp"``を追加します。

```js
        <v-calendar
          ref="calendar"
          :now="today"
          :value="today"
          :events="events"
          color="primary"
        ++locale="ja-jp"

```
![スクリーンショット 2022-03-18 13.40.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641519/03bb5681-6b5f-7c3f-9764-d8f617c9cf71.png)

さらにフォーマットを変更したいときは、formatのオプションを追加します。オプションを追加すること見やすいフォーマットに整えられます。
```js
        <v-calendar
          ref="calendar"
          :now="today"
          :value="today"
          :events="events"
          color="primary"
          locale="ja-jp"
        ++:day-format="(timestamp) => new Date(timestamp.date).getDate()"
        ++:month-format="(timestamp) => (new Date(timestamp.date).getMonth() + 1) + ' /'"
```
![スクリーンショット 2022-03-18 13.45.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/641519/093f7caf-0f90-5673-8f87-665785ce8d70.png)

<a id="#Chapter2"></a>
# Vuexで分割したいとき
### 値の管理

``Vuex、store``を使用する際は注意が必要です。
例えば、サーバー側のRailsをapiモードにして、NuxtまたはVueから値を送りたい事もあります。
サーバーとのやりとりはstoreまたはVuexを使用して行うことが多いかと思いますが、その際にstateではカレンダーに表示する``evnts``を管理することになります。
``events``には``name、color、start、end``などの予定を作成するために必要な情報を格納します。
その際に``events``だけ管理してしまうと思わぬエラーで躓きます。
例えばドラッグ&ドロップを使用してカレンダーを作成すると、以下のエラーが起こります。

```
[vuex] do not mutate vuex store state outside mutation handlers.
```
これは``evets``の値を``mutation``以外から変更しようとすると起こるエラーですが、``events``だけ``state``で管理している場合、ドラッグ&ドロップするときに勝手に``events``にアクセスしてしまいます。これは内部的な処理で、``v-calendar``を使用しているテンプレート内では直接確認できませんが、恐らく``mouse:down``イベントが悪さをしています。解決方法としては。変更を与えているであろう他のメソッドも``computed``で管理するしかありません。


### サーバーから受け取ったデータの取り扱い
api通信で値を送った後のレスポンスを受け取るには``push``を使う必要があります。
一つ一つのデータを取りだしてから``push``を行わないとエラーが出ます。
例えば、``mounted``を使ってページ更新時に値を取得しようとします。
その場合は下記の通り一つずつ取得しないとエラーになります。
``response``を``data``で取り出さずに直接``setEvent``に渡してしまうと、Vueがレンダリングのために準備していた``events``がサーバーから受け取った``response``で上書きされてしまうからです。

追記：``Vuex``でevent配列を管理する場合は``mounted``のすぐ後にevents配列を初期化する処理を入れることをお勧めします。ブラウザバックなどを行なったときに``Vuex``が値を保存しているため、保存したイベントがレンダリング分表示されます。なのでレンダリング時にはリセットの処理があったほうがいいです。

```js
mounted () {
     // state.eventsを空にする処理
    this.$axios.$get(XXXXXX)
      .then((response) => {
        let data
        response.forEach((res) => {
          data = {
            id: res.id,
            name: res.name,
            color: res.color,
            start: res.start,
            end: res.end,
            updated_at: res.created_at,
            timed: res.timed,
          }
          this.$store.commit('setEvent', data)
        })
      })
  },
```
store
```js
export const state = () => ({
  events: [],
})

export const mutations = {
 // イベント追加
  setEvent (state, payload) {
    state.events.push(payload)
  },
}
```

# まとめ

Vuetifyのカレンダーは細かい情報が少なく大変です。公式のオプションの説明はかなり簡素で、情報を集めるのに苦労しました・・
私は特にVuexで躓きました。値の管理に時間がかかってしまいました。
<a id="#reference"></a>
# 参考文献
- [Vuetify公式](https://vuetifyjs.com/ja/components/calendars/)
- [Vuetifyで簡単にカレンダーを表示する](https://qiita.com/youichiro/items/7c65bad988852f1654d6L)
- [VueStacks Calendar Series (2/3): Adding Vuex](https://medium.com/@curvingcreekprints/build-an-event-calendar-with-vue-js-vuetify-and-firebase-part-2-adding-vuex-a52fed4af596)