Vue3のComposition APIを試してみる
前回、Rails + vue3 + Typescriptの導入をしました。
そのコードをComposition APIを使って書き直していきます。
前回の記事
前回までのソースコード
Composition APIとはなんぞや?という方は、こちらの記事がわかりやすかったので読んでみてください。
この記事では、既存のコードをどのようにComposition APIに置き換えたかをまとめます。
コードの書き換え
dataやmethod、watchで定義していたものは全部setupに定義します。
watchはこの記事では扱ってないので、ドキュメントをみてください。
data -> setup に変更
一番ここでつまずきました。
refとreactiveというメソッドを使って書き換えるのですが、使い分けがよくわからなかったです。
vueのドキュメントからref、reactiveの説明を抜粋すると
Vue 3.0 では、このように新しい ref 関数にとってあらゆる変数をリアクティブにすることができます
ここでリアクティブ?となりました。(この記事の最後にリアクティブの説明を載せてみたので読みたい方は読んでください)
とりあえず、objectはreactive、numberとかstringとか(プリミティブ)はrefで定義しましょうという感覚です。
実際にコードを変換すると、、、
data() {
return {
form: {
name: ''
} as Form,
users: [] as User[]
}
},
import {defineComponent, reactive} from 'vue'
// ...
setup() {
const form = reactive<Form>({name: ''})
const users = reactive<User[]>([])
return {form, users}
}
これでtemplateの中でformやusersにアクセスできるようになります。
methods -> setup
methods: {
async createUser() {
const user = await createUser(this.form)
this.users.push(user)
this.form.name = ''
}
},
import {defineComponent, reactive, ref} from 'vue'
import * as UserApi from '/@/apis/users_api' // apiの読み込み方も変更しました。
// ...
setup() {
const form = ref<Form>({name: ''}) // !!refになっている!!
const users = reactive<User[]>([])
const createUser = async () => {
const user = await UserApi.createUser(form.value)
users.push(user)
form.value = {name: ''}
}
return {form, users, createUser}
},
ただ単にcreateUserを移して、returnするだけでいいや。。。と思いきや、formがrefに変更しています。
なんでこうしたかというと、objectの中身を変更ではなく、object自体を変更したいからです。
formのnameだけを変更したいのであれば、reactiveのままでform.name = ''
(中身の変更)にすればよかったです。
が、form = {name: ''}
(object自体の変更)のように書きたかったので、reactiveからrefに変更しました。(ポインタと似てますね)
createdAt -> setup
async created() {
this.users = await getUsers()
}
ここで問題になってくるのが、普通にsetupをasyncに置き換えても動作しないということです。
これを解決するために、suspense
という機能を使います。
suspenseは非同期処理の処理中の時(#fallback)と処理完了時(#default)、に表示するコンポーネントを切り替えることができる機能です。
<template>
<suspense>
<template #fallback>
<p>処理中</p>
</template>
<template #default>
<p>完了</p>
<!-- ここにsetupがasyncのコンポーネントを配置できる -->
</template>
</suspense>
</template>
async用のコンポーネントを別に用意しないと行けないので、User.vueを作成して、それを<template #default>
の配下でロードするようにします。
これは記事に書くと長ったらしくなるので、githubのコードを実際にみてください。
App.vue
User.vue
最後に
Composition APIに変更も意外と簡単にできました。
今度は、Vuexの導入をしたいと思います。
付録
リアクティブとは
まとめてみましたが、いまいちだったので気力がでたら書き直します。
色々調べた結果、こんな考えにまとまりました。
コードで書くとわかりやすそうなのでコードで説明します。
let i = 1
console.log(i) // 1
i + 1
console.log(i) // 1
これをみてみると当たり前じゃん!ってなると思います。これがリアクティブではないということです。
逆にリアクティブとはこんな感じです。
let obj = {}
console.log(obj) // {}
obj.message = 'hello!'
console.log(obj) // {messag: 'hello'}
リアクティブはオブジェクトの変更に対して追随するということです。
ポインタを知っている方であれば、refはポインタ、reactiveは中身という認識でいいと思います。
Discussion