Vue 2.7で Composition APIとscript setupを使ってみる

‘‘‘
vue 2.7.16
@vitejs/plugin-vue2 2.3.3

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208807/142671b7-5d13-681e-51dd-5423e648a9c8.png)


```json:package.json
{
  "name": "vue2-project",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "vue": "^2.7.16"
  },
  "devDependencies": {
    "@vitejs/plugin-vue2": "^2.3.3"
  }
}
```

```html:index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Vue</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>
```

```config:vite.config
// vite.config.js
import vue from '@vitejs/plugin-vue2';

export default {
  plugins: [vue()],
};
```
```vue:App.vue
<template>
  <div id="app">
    <Sample />
  </div>
</template>

<script>
import Sample from './components/Sample.vue';

export default {
  name: 'App',
  components: {
    Sample,
  },
};
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

```js:main.js
import Vue from 'vue/dist/vue.esm';
import App from './App.vue';

new Vue({
  render: (h) => h(App),
}).$mount('#app');
```

useCounter.jsは、最初からComposition API で書く

```js:useCounter.js
import { ref } from 'vue/dist/vue.esm.js';

export const useCounter = (defaultCount = 0) => {
  const count = ref(defaultCount);
  const increment = () => count.value++;
  const decrement = () => count.value--;

  return { count, increment, decrement };
};
```

## Sample.vueをOptions APIで書いた場合

```vue:Sample.vue
<template>
  <div>
    <p data-cy="counter">Times clicked: {{ count }}</p>
    <button @click="increment" data-cy="increment">increment</button>
    <button @click="decrement" data-cy="decrement">decrement</button>
  </div>
</template>

<script>
import { useCounter } from './useCounter.js';

export default {
  data() {
    const { count, increment, decrement } = useCounter();
    return { count, increment, decrement };
  },
};
</script>
```

## Sample.vueをComposition APIで&lt;script setup&gt;を使わない場合

```vue:Sample.vue
<template>
  <div>
    <p data-cy="counter">Times clicked: {{ count }}</p>
    <button @click="increment" data-cy="increment">increment</button>
    <button @click="decrement" data-cy="decrement">decrement</button>
  </div>
</template>

<script>
export default {
  setup() {
    const { count, increment, decrement } = useCounter();
    return { count, increment, decrement };
  },
};
</script>
```

## Sample.vueをComposition APIで&lt;script setup&gt;使った場合

```vue:Sample.vue
<script setup>
import { useCounter } from './useCounter.js';
const { count, increment, decrement } = useCounter();
</script>

<template>
  <div>
    <p data-cy="counter">Times clicked: {{ count }}</p>
    <button @click="increment" data-cy="increment">increment</button>
    <button @click="decrement" data-cy="decrement">decrement</button>
  </div>
</template>
```

## Vue 2.7 で Composition API を使ったときにはまったところ

import { ref } from 'vue';をimport { ref } from 'vue/dist/vue.esm.js';にしたら動いたので、
vue.esm.js を明示的にインポートする必要がありそう
ref の変更が反映されない場合は、まず vue.esm.js を試す。