Vue2のプロジェクトはVue3に上げるべき…？

Nuxt.jsもついに3系がリリースされ、そろそろVueも3系にupgradeしなければ‥
とみなさんがお思いであると思いますので、公式の発表を掻い摘んでまとめていきます。

# composiotion API

Vue 3.xから新たに追加された機能では有りませんが、これからはcomposition API前提での話になってきそうなので、composition APIについても簡易的にまとめておきます。

```js:composition.vue
import { computed, defineComponent, reactive, } from 'vue'
export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: {
      type: String,
      required: true
    }
  },
  setup(props) {
    const state = reactive<State>({
      todos: []
    })
    const result = computed(() => state.todos.sort((a, b) => {
      return b.createdAt.getTime() - a.createdAt.getTime()
    }))

    return {
      result
    } // ここで返されるものはコンポーネントの他のオプションで使用可能です
  }
}
```


## setupメソッド

Options API（composition API以前の構造）と異なり、Vue component内でのdata,methods,computed,ライフサイクルメソッド(mounted,createdなど)などの区別がなくなり、全てがsetupメソッドの中に記述されています。（mounted -> onMountedなど多少の変化はあり）
一方で、componentsやpropsの記述は以前と同様に記述します。

setupメソッド内のデータは、returnされたものだけがtemplate内で使用できるようになります。
そのため、setupメソッド内でstateという変数を宣言したとしてもreturnしない場合はこれを使用することはできません。stateの値は直接使用せずに、computedを通して使用するという意図を伝えることができます。

## thisの削除
全てがsetupメソッド内に記述された結果、他のプロパティにアクセスする際にthisが不要になりました。以前までのVueではこのthisの制約によりアロー関数で記述することが敬遠されていた(const self = this;など一度定義しないと内部で使用できなかったため)のですが、Composition APIではアロー関数により記述が可能になりました。



# Template Directives

## v-modelのデータバインディングの簡略化
v-modelを渡すだけで、親のComponentとデータバインディングするための Props 及び Emit が暗黙的にバインドされます。emitで受け取る側の処理が簡略的に書けるようになりました。

-- POINT --
v-bindの.sync修飾子とコンポーネントmodelオプションが削除され、v-modelの引数に置き換えられました。

```js:parent.vue
<ChildComponent v-model:title="pageTitle" />

<!-- 上記は下記の省略形です -->

<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
```

```js:child.vue
<script>
export default {
  props: {
    modelValue: String // vue2.xでは value:String でした
  },
  emits: ['update:modelValue'],
  methods: {
    changePageTitle(title) {
      this.$emit('update:modelValue', title) // vue2.xでは this.$emit('input', title) でした
    }
  }
}
</script>
```


## v-ifのkeyが不要に

v-if/v-else/v-else-ifを使用する際、keyを用いることが推奨されていましたが、Vue 3.xになって不要になりました。

```js:vue
<!-- Vue 2.x -->
<div v-if="condition" key="yes">Yes</div>
<div v-else key="no">No</div>

<!-- Vue 3.x -->
<div v-if="condition">Yes</div>
<div v-else>No</div>

```


v-forの使用する際には、v-for自体に:keyをもたせることができ、子にkeyは不要になりました。
また、Vue 2.xまではtemplateにkeyをもたせることができませんでしたが、Vue 3.xでは持たせることができ、子のkeyは省略することができます。


```js:vue
<!-- Vue 2.x -->
<template v-for="item in list">
  <div v-if="item.isVisible" :key="item.id">...</div>
  <span v-else :key="item.id">...</span>
</template>

<!-- Vue 3.x -->
<template v-for="item in list" :key="item.id">
  <div v-if="item.isVisible">...</div>
  <span v-else>...</span>
</template>

```

Vue 2.xでは、v-ifとv-forが同じ要素に設定している場合、v-forが優先されてきましたが、Vue3からはv-ifが優先されます。

## v-bind

Vue 2.xの場合はすでに指定されている場合、v-bindのほうが弱かったですが、Vue 3.xでは指定する属性の順番で優先順位が変わります。

```js:vue2.vue
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>

<!-- result -->
<div id="red"></div>
```

```js:vue3.vue
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="blue"></div>

<!-- template -->
<div v-bind="{ id: 'blue' }" id="red"></div>
<!-- result -->
<div id="red"></div>
```

#Components

## emitを明示的に定義

これまでcomponentではpropsはscript内に定義していましたが、Vue 3.xではemitも書かなくてはなりません。
これにより、途中からプロジェクトに入った人などがより速やかにコードが理解しやすくなるかと思います。

```js:emit.vue
<!-- Vue 2.x -->
<template>
  <div>
    <p>{{ text }}</p>
    <button v-on:click="$emit('accepted')">OK</button>
  </div>
</template>
<script>
  export default {
    props: ['text']
  }
</script>


<!-- Vue 3.x -->
<template>
  <div>
    <p>{{ text }}</p>
    <button v-on:click="$emit('accepted')">OK</button>
  </div>
</template>
<script>
  export default {
    props: ['text'],
    emits: ['accepted']
  }
</script>
```

# Vue 3.x まとめ

Vue 2.xでは暗黙的に動作していた部分をVue 3.xでは定義しなくてはいけなくなるものが多く、コードの保守性が向上したのではないかと思います。ただ、そのせい？で破壊的な変更が多く（特にOption　 API -> composition API）、既存のVue 2.xを使用しているプロジェクトをVue 3.xに上げるのはひどく大変なものだと考えられます…
Option APIで動作自体はするようですが…

新規プロジェクトではVue 3を使ってみたいなと思います！


## 参考
Vue.js公式：https://v3.vuejs.org/guide/migration/introduction.html#overview