Vue3のComposition APIについての学習

## 概要
以下の動画の文字起こし＆理解の整理
https://www.youtube.com/watch?v=XIpQLdcqawc

## Composition APIとは
柔軟にコンポーネントをかける

### なぜ使うのか
- 保守性の向上
- 再利用性の向上

## Vue2 -> Vue3
Vue2で書かれたコード

```vuejs
// src/components/CounterMouse.vue
<template>
  <div @mousemove="updateMouse">
    <div>
      Count is {{ count }}, count * {{ times }} is {{ multiplicationResult }}
      <button @click="increment">
        +
      </button>
    </div>
    <div>Mouse is at {{ mousePosition.x }}, {{ mousePosition.y }}</div>
  </div>
</template>

<script>
export default {
  props: {
    times: {
      type: Number,
      default: 2
    }
  },
  data() {
   return {
      mousePosition: {
      x: 0,
      y: 0
    },
    count: 0
   }
  },
  computed: {
    multiplicationResult() {
      return this.count * this.times;
    }
  },
  watch: {
    count() {
      setTimeout(() => {
        alert('3 seconds have passed since the value changed');
      }, 3000);
    }
  },
  methods: {
    increment() {
      this.count += 1;
    },
    updateMouse(event) {
      this.mousePosition.x = event.clientX
      this.mousePosition.y = event.clientY
    },
  }
}
</script>
```


Vue3で書き換えたコード

```vuejs
// src/components/CounterMouse.vue
<template>
  <div @mousemove="updateMouse">
    <div>
      <!-- you can omit ".value" to get the value in template -->
      Count is {{ count }}, count * {{ times }} is {{ multiplicationResult }}
      <button @click="increment">
        +
</template>

<script>
// "reactive" can be passed only object as argument
// "ref" can be passed not only object such as Number, String, and so on
// you should access the value with ".value" if you use "ref"
import { reactive, ref, computed, watch } from '@vue/composition-api';
export default {
  props: {
    times: {
      type: Number,
      default: 2
    }
  },
  // "setup" is executed before "beforeCreate"
  // That's why "this" cannot be used
  // "setup" has first argument of props
  setup(props) {
    // data
    const mousePosition = reactive({
      x: 0,
      y: 0
    });
    let count = ref(0);

    // methods
    const increment = () => {
      count.value += 1;
    };
    const updateMouse = (event) => {
      mousePosition.x = event.clientX
      mousePosition.y = event.clientY
    };

    // computed
    const multiplicationResult = computed(() =>  {
      return count.value * props.times;
    });

    // watcher
    watch(count, () => {
      setTimeout(() => {
        alert('3 seconds have passed since the value changed');
      }, 3000)
    })

    return {
      mousePosition,
      count,
      increment,
      updateMouse,
      multiplicationResult
    }
  },
}
</script>
```

### 補足
#### reactiveとは
仮に以下のようなコードがあった時、依存関係のあるものが変更された時に更新される状態をreactiveと呼ぶ
つまり、xが変化すれば、aの値も変化する状態

```javascript
let x = 1;

let a = x + 3;

x = 3;

a is 4? or 6? 
```

## 保守性をあげる（見やすくする）

```javascript
// src/components/CounterMouse.vue
  :
  :
  setup(props) {
    // Processing for "count"
    let count = ref(0);
    const increment = () => {
      count.value += 1;
    };
    const multiplicationResult = computed(() =>  {
      return count.value * props.times;
    });
    watch(count, () => {
      setTimeout(() => {
        alert('3 seconds have passed since the value changed');
      }, 3000)
    })

    // Processing for "mousePosition"
    const mousePosition = reactive({
      x: 0,
      y: 0
    });
    const updateMouse = (event) => {
      mousePosition.x = event.clientX
      mousePosition.y = event.clientY
    };

    return {
      mousePosition,
      count,
      increment,
      updateMouse,
      multiplicationResult
    }
  },
}
```
Vue2はオプションごとにまとまっているが、機能ごとにまとめることができる


## 再利用性をあげる
Vue2でのmixinは処理を追うのを難しくさせる場合があるのと、名前のコンフリクトが起こる可能性がある

```javascript
// src/components/CounterMouse.vue
:
:
import { ref, computed, watch } from '@vue/composition-api';
import { usePosition } from '../util-functions/position'

export default {
    :
    :
    // Processing for "mousePosition"
    // const mousePosition = reactive({
    //   x: 0,
    //   y: 0
    // });
    // const updateMouse = (event) => {
    //   mousePosition.x = event.clientX
    //   mousePosition.y = event.clientY
    // };

    // you can change names to avoid names confliction
    const { position: mousePosition, updatePosition: updateMouse } = usePosition();

    return {
      :
      :
      multiplicationResult
    }
  },
}
```

```javascript
// src/util-functions/position.js
import { reactive } from '@vue/composition-api'

export const usePosition = () => {
  const position = reactive({
    x: 0,
    y: 0
  });

  const updatePosition = (event) => {
    position.x = event.clientX
    position.y = event.clientY
  };

  return { position, updatePosition }
}

```


## 最終的なコード

```vuejs

<template>
  <div @mousemove="updateMouse">
    <div>
      <!-- you can omit ".value" to get the value in template -->
      Count is {{ count }}, count * {{ times }} is {{ multiplicationResult }}
      <button @click="increment">
        +
      </button>
    </div>
    <div>Mouse is at {{ mousePosition.x }}, {{ mousePosition.y }}</div>
  </div>
</template>

<script>
// "reactive" can be passed only object as argument
// "ref" can be passed not only object such as Number, String, and so on
// you should access the value with ".value" if you use "ref"
import { ref, computed, watch } from '@vue/composition-api';
import { usePosition } from '../util-functions/position'

export default {
  props: {
    times: {
      type: Number,
      default: 2
    }
  },
  // "setup" is executed before "beforeCreate"
  // That's why "this" cannot be used
  // "setup" has first argument of props
  setup(props) {
    // Processing for "count"
    let count = ref(0);
    const increment = () => {
      count.value += 1;
    };
    const multiplicationResult = computed(() =>  {
      return count.value * props.times;
    });
    watch(count, () => {
      setTimeout(() => {
        alert('3 seconds have passed since the value changed');
      }, 3000)
    })

    // Processing for "mousePosition"
    const { position: mousePosition, updatePosition: updateMouse } = usePosition()

    return {
      mousePosition,
      count,
      increment,
      updateMouse,
      multiplicationResult
    }
  },
}
</script>

```