［Vue3］piniaざっくりまとめ

編集中、見た目の確認のために公開

# 概要
piniaはデータの変更、加工処理など管理を行う。

# piniaの設定
viteでvueをinitする際にpiniaをyesとすれば、`stores`ディレクトリが生成され`counte.ts`が作成される。
後述に説明するが、piniaはimportして使用するため、ディレクトリやファイル名は気する必要はないが、ここでは初期設定のまま解説する。
また、この際に`main.ts`に`app.use(createPinia())`が追記されるが、counter.tsを使用しているページは作成されないため独自に実装する。

```
src
...
 ├─ stores
     ├─ coutets.ts
 ...
```

# pinia初期ファイルの中身
初期ファイルである`store/counter.ts`の中身について解説する。
まず、piniaは`defineStore()`関数をインポートしてその実行結果をuseCounterStoreとしてエクスポートしている。
これを各コンポーネントでインポートすることにより、counter.tsで作成した変数や関数を使用する。


```counter.ts
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }

  return { count, doubleCount, increment }
})
```

## defineStore()関数
piniaのキーとなる`defineStore()` 関数について。

### 引数
`defineStore()` は以下の２つの引数を受け取る。
・id
・options

<table>
	<tr>
		<td>引数</td>
		<td>内容</td>
	</tr>
	<tr>
		<td>id</td>
		<td>ストアを識別するための一意な名前。<br>（ストアのファイル名と同じにするとわかりやすい）</td>
	</tr>
	<tr>
		<td>options</td>
		<td>ストアを定義するためのオプション。<br>Optionsオブジェクトまたは Setup関数のいずれかを受け取る。</td>
	</tr>
</table>

### id（第一引数）
ストアは複数定義できるため第1引数にはストアを識別するための一意な名前（id）を指定する。
任意の名前を付けられるが、ストアのファイル名と同じにすると関係がわかりやすい。

### options（第二引数）
optionsには以下のいずれかを受け取ってストアを定義することができる。

・Optionsオブジェクト（Option Stores）
・Setup関数（リアクティブなオブジェクトを返す関数）（Setup Stores）

初期サンプルではref()で値を操作したSetup関数を引数としている。

#### optionsオブジェクト
初期サンプルの内容をoptionsオブジェクトで記述した内容を下記する。

`state`プロパティは、オブジェクトを戻り値とするアロー式を記述する。
`getter`プロパティは、オブジェクトを記述する。
この際、オブジェクトのプロパティ名がgetter名となる。
`actions`プロパティでは、オブジェクトに関数を記述する。

<table>
  <tr>
    <td>optionsオブジェクト</td>
    <td>内容</td>
  </tr>
  <tr>
    <td>state</td>
    <td>データ本体でデータの初期値を返す関数として定義する。<br>データは必要な数だけ「名前：初期値」の形式で列記できる。</td>
  </tr>
  <tr>
    <td>getter</td>
    <td>state のデータに対する算出プロパティ（computed オプションに相当）。<br>既存のstateの値をもとに算出するためのプロパティ。<br>第1引数にstateを受け取り値を返す関数。</td>
  </tr>
  <tr>
    <td>actions</td>
    <td>stateの値を更新する関数。<br>ストアのインスタンスにthisでアクセスできる。</td>
  </tr>
</table>

```countes.ts
import {defineStore} from "pinia";

interface State {
	count: number;
}

export const useCounterStore = defineStore("counter", {
	state: (): State => {
		return {
			count: 0
		};
	},
	getters: {
		doubleCount: (state): number => {
			return state.count * 2;
		}
	},
	actions: {
		increment(): void {
			this.count++;
		}
	}
});
```

#### setup関数
setup関数の意味をoptionsオブジェクトに合わせて解説する。

<table>
  <tr>
    <td>内容</td>
    <td>optionsオブジェクトに沿った名称</td>
  </tr>
  <tr>
    <td>変数名 = ref()</td>
    <td>stateに相当</td>
  </tr>
  <tr>
    <td>変数名 = computed()</td>
    <td>getter</td>
  </tr>
  <tr>
    <td>function()</td>
    <td>actions</td>
  </tr>
</table>

```counter.ts
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
    // state
    const count = ref(0)
    // getter
    const doubleCount = computed(() => count.value * 2)
    // action
    function increment() {
        count.value++
    }

  return { count, doubleCount, increment }
})
```



### どちらの構文を使用するか

Setup関数はソースが簡潔だが何を意味しているか判断する必要があり、Optionsオブジェクトでは各プロパティ名によりソースが明確だが煩雑になる。

[公式ドキュメント](https://pinia.vuejs.org/core-concepts/#what-syntax-should-i-pick)
`VueのコンポジションAPIとオプションAPIと同様に、最も使いやすいものを選択してください。 `
`よくわからない場合は、最初にOption Stores（optionsオブジェクト）を試してください。`


### 戻り値
`defineStore()`は定義されたストアのインスタンスを生成する関数を返す。
すトアのインスタンスを生成する関数と書いているが、defineStore()の戻り値の関数はコンストラクタではなくgetter関数（useXxxxStore）となる。
戻り値のgetter関数はコンポーネントから参照できるように名前付きエクスポートする。


# ストアファイルの利用
npmからinitした時点ではcounter.tsを使用したページが作成されないApp.vueにサンプルを作成する。
コンポーネントからcounter.tsでエクスポートしたuseCounterStoreをインポートして使用する。
この際、インポートしたuseCounterStore()関数は変数に格納することで、この変数がストアオブジェクトとなる。

```App.vue
<script setup lang="ts">
import { computed } from "vue";
import { useCounterStore } from "@/stores/counter";

const counterStore = useCounterStore();

const count = computed(
  (): number => {
    return counterStore.count;
  }
);

const doubleCount = computed(
  (): number => {
    return counterStore.doubleCount;
  }
);

const onIncrementClick = () => {
  counterStore.increment();
};

</script>

<template>
  <p>count: {{ count }}</p>
  <p>doubleCount: {{ doubleCount }}</p>
  <button v-on:click="onIncrementClick">加算</button>
</template>
```

## ストアの各値の利用
ストアのstate、getter、actionの各値の利用方法が異なる。

### stateとgetter
`state`と`getter`はストアオブジェクト（格納した変数）に`.state名`または`.getter名`を記述することで、その値を利用できる。
ただし、上記のサンプルではクリック毎に値が再計算されるためstate変数もgette変数もcomputed()関数を利用して算出プロパティとする必要がある。

```
const 変数名 = computed(
    (): データ型 => { 
        return ストアオブジェクト.state名; 
        または
        return ストアオブジェクト.getter名; 
    } 
);

```

### action
`action`を使用する場合はストアオブジェクト（格納した変数）から直接action関数を呼び出せる。

```
ステートオブジェクト.action関数名();
```

# defineStore()ののgettersとactionsに引数を渡す
defineStore()の第二引数にoptionsオブジェクトを渡す場合、`getters`と`actions`に引数の渡す方法が異なる。

## getters
gettersオブジェクトに引数を渡す場合、関数を戻り値とする。
その関数に引数を設定することで、コンポーネントからひきすうを渡せるようになる。

```:記法
getters: {
	getter名: (state) => {
		return (引数: 引数の型): 戻り値の型 => {
			stateを元に加工するデータの処理;
            return 加工データ;
		};
	},
    ...
},
```

## actions
actionsオブジェクトに引数を渡す場合は、通常の関数の引数を渡すように定義する。

```:記法
actions: {
	action名(引数: 引数の型): 戻り値の型 {
			this.state.処理;
		};
	},
    ...
},
```

# 参考
[Vue の基本的な使い方 (5) Pinia を使って状態管理](https://www.webdesignleaves.com/pr/plugins/vue-basic-05.html)