Vue3 Composition APIのrefとreactiveをざっくりと理解する
導入
今週、社内でVue3についての勉強会がありました。
その中で、一番気になったComposition APIのrefとreactiveについて調べることにしました
自分が理解できた箇所のみをまとめた浅い記事ですがご容赦ください。
リアクティブとは?
refとreactiveの話をする前に、リアクティブとは何かということについて理解する必要があります。
リアクティブとは、「ある変数を書き換えた際に既に定められた関係性によって、他の変数が更新される / 事前に定めた動作が実行される」だと僕は理解しています。
簡単な例だと以下になります。
const sample = reactive({a: 1}) const sample2 = computed(() => sample.a + 100) console.log(sample2.value) // 101 sample.a = 10 console.log(sample2.value)// 110
リアクティブなデータなので、sample.aを書きかえた際にsample2が更新されています。
refとreactiveの基本
ref
プリミティブな値をアクティブで可変なrefオブジェクトを返す関数です。 refオブジェクトにはvalueというプロパティがあり、これによってアクセスできるようです。
const count = ref(0) console.log(count.value) // 0 count.value++ console.log(count.value) // 1
template内で使う場合は、refがレンダーコンテキストのプロパティとして返されるようで、valueプロパティでアクセスする必要はないようです。
<template> <div>{{ count }}</div> </template> <script> export default { setup() { return { count: ref(0) } } } </script>
reactive
オブジェクトをリアクティブなProxyオブジェクトにして返す関数です。 この際のリアクティブへの変換はディープコピーのようですが、返されるプロキシは元のオブジェクトと同一ではないようです。
const obj = reactive({count: 1}) console.log(obj.count) // 1 obj.count++ console.log(obj.count) // 2
refとreactiveの違い
リアクティブ化できる値
reativeはプリミティブな値はリアクティブにできませんが
refは、プリミティブな値以外(配列やオブジェクト等)でもリアクティブにできるようです。
// reactiveはプリミティブな値をリアクティブにすることはできない const number = reactive(0) console.log(number) // undefined // refはプリミティブな値以外(配列やオブジェクト等)でもリアクティブにできる const str = ref('hoge') const array = ref([1, 2, 3, 4]) const obj = ref({a:1, b:1}) console.log(isRef(str)) //true console.log(isRef(array)) //true console.log(isRef(obj)) //true console.log(obj.value.a) // 1 obj.value.a = 100 const sample = obj.value.a = 100 + 1 console.log(sample) // 101
リアクティブの消失
reactiveでリアクティブにしたデータを、リアクティブのまま分割して使うことは出来ないようです。 文章だとわかりにくいので、以下にサンプルのコードを書きます
count.ts(reactiveなオブジェクトをセットする関数)
import { reactive } from '@vue/composition-api' export function setCountReactive() { const obj = reactive({ count: 1 }) return obj }
home.vue
<template> <div> <button @click="incrementA()">足す</button> {{ obj.count }} <button @click="incrementB()">足す</button> {{ count }} </div> </template> <script lang="ts"> import { setCountReactive } from './count' export default { setup() { /// 通常パターン const obj = setCountReactive() function incrementA() { return obj.count++ } // リアクティブが消失してしまうパターン let { count } = setCountReactive() function incrementB() { return count++ } return { incrementA, incrementB, obj, count, } } } </script>
こういう場合に、リアクティブに扱いたい場合はToRefsを仕様して、refでラップしてあげればいいようです。
count.ts(reactiveなオブジェクトをセットする関数)
import { reactive, toRefs } from '@vue/composition-api' export function setCountReactive() { const obj = reactive({ count: 1 }) return toRefs(obj) }
ただし、refでラップする場合はvalueプロパティでアクセスする必要があります。
home.vue
<template> <div> <button @click="incrementA()">足す</button> {{ obj.count }} <button @click="incrementB()">足す</button> {{ count }} </div> </template> <script lang="ts"> import {setCountReactive} from './count' export default { setup() { /// 通常パターン const obj = setCountReactive() function incrementA() { return obj.count.value++ } // リアクティブが消失してしまうパターン let {count} = setCountReactive() function incrementB() { return count.value++ } return { incrementA, incrementB, obj, count, } } } </script>
refとreactiveの使い分け
ここまで調べて、refとreactiveはどのように使い分けるのか?という疑問がわきました。
まだ有用な使い分けの仕方はわかりませんが、refとreactiveの違いでも書いたように
プリミティブな値を使う場合はref、それ以外の場合はreactiveを使っておけば間違いはないのかなと思います。
ただ、「オブジェクトのある特定のプロパティだけリアクティブに扱いたい」などの場合はreactiveでtoRefsを使えばいいようです。
終わりに
今回は、refとreactiveについて書きました。
Vue3での変更点や便利そうな新機能など、まだまだキャッチアップできていない情報がたくさんあるので
今後も機会があれば、アウトプットしていきたいと思います。