はじめに
前回の記事からの続きになります
Vue3.xから採用予定のCompositionAPIとVue2.xを比較してみる
前回の記事を書いた際にref
とreactive
の違いについて
これらについてはまだ実装しながら確認している最中なので、また別途まとめたいと思います。
と記載していました。
今回はそれらについて実装を進めつつまた残しておきたいと思います。
なお確認の際に実装したソースコードは以下のgithubにあげています。
vue-composition-api-test
前提とする環境
VueCLI v4.0.5
node v10.16.0
yarn v1.13.0
CompositionAPIのリアクティブなオブジェクト
compostionAPIでリアクティブなオブジェクトを定義する場合、refとreactiveの2種類があります。
それらについてふれていきます。
refについて
refは単一のvalueプロパティをもつプリミティブオブジェクトです。
イメージ的には以前data()で定義されていたものが近いです。
呼び出しかた
vue2.x系で使用する場合はcompositionAPIからインポートします。
import { createComponent, ref } from "@vue/composition-api";
定義のしかた
setup()
関数内で以下のように変数を定義します。
const RefHelloCount = ref(1);
配列を定義することも可能です。
const Animals = ref(["cat", "dog", "hamster"]);
以下のようなデータを定義する場合は後述のreactive
を使用します。
let RefAnimalObjects = ref({
cat: 1,
dog: 2
});
値へのアクセス方法
変数の値には、setup()
関数内のメソッドなどで呼び出す場合は変数名.value
で、テンプレートからはそのまま{{変数名}}
で呼び出します。
それぞれ確認していきます、
setup()関数内での呼び出し
数字を増加させるだけのメソッドを導入してみます。
以下のように記述すると失敗します。
const incrementHello = () => {
RefHelloCount++;
};
なぜならref
で定義された変数はプリミティブなオブジェクトであるからです。
consoleに出力してみたデータを確認したところ以下のような表示になります。
そのため先ほどの処理を以下のように修正します。
const incrementHello = () => {
refHelloCount.value++;
};
これで問題なく動作します。
templateでの呼び出し
tempalteへの表示を行う際にはvalue
の表記はせずに記載しても問題なく表示がなされます。
APIの内部でvalue
をexpose
するような処理が走っているのでvalue
なしの状態で記載します。
<p>{{ RefHelloCount }}</p>
注意点
- setup関数内で呼び出す際の扱い方とtemplate内での呼び出し方の違い
- templateないで呼び出すときは
value
がなくても大丈夫。API側がよしなに変更してくれる - setup関数内で呼び出すときは
value
が必要
- templateないで呼び出すときは
- オブジェクトを定義する場合は
reactive
を使用する
reactive
もう一つのreactive
を確認します。
こちらもrefと同じようにcomposition-api
からインポートします。
import { createComponent, reactive } from "@vue/composition-api";
定義のしかた
先ほど一つ一つrefにで定義して分散して記載していたものをまとめることができます。
returnする際にも定義した一つの変数を記載すればすみます。
const ReactiveData = reactive({
count: 1,
ReativeAnimals: ["cat", "dog", "hamster"]
});
return {
ReactiveData
};
値へのアクセス方法
上記のように定義した場合、setup()
関数内で使用する場合は変数名.key
でアクセスします。テンプレート変数で利用する場合も変数名.key
(valueは不要)でアクセスをします。
それぞれ確認していきます。
setup()関数内での呼び出し
変数名.key
で該当の値にアクセスします。
なおこの際にvalue
は不要です。
この点に関してはref
で作成したデータにアクセスするよりはシンプルでわかりやすいように思えます。
const incrementHelloReactve = () => {
ReactiveData.count++;
};
templateでの呼び出し
値へのアクセスで触れましたが、template
内で該当の変数を呼び出すのにref
に比べて冗長になりがちです。
return {
ReactiveData
};
↓ 上記データをtemplate内で使用する
<p>
{{ReactiveData.count}}
{{ReactiveData.animals}}
</p>
そこでこのオブジェクトをプレーンなオブジェクトに変換するtoRefs
というメソッドを利用します。
これを利用するとそれぞれのプロパティがplainなオブジェクトに変換され、templateから呼び出す際に冗長な書き方が不要になります。
return {
...toRefs(ReactiveData)
};
return分の中で上記のように記載するとtemplate
内での記述が以下のように変わります。
<p>
{{count}}
{{animals}}
</p>
非常にシンプルになりました。
API内部で何をやっているのか
compostionAPIの内部で何をやっているのか確認してみました。
node_modules/@vue/compostion-api/vue-composition-api.module.js
の
174行目から191行目にそれらしき記述があります。
function isPlainObject(x) {
return toString(x) === '[object Object]';
}
function toRefs(obj) {
if (!isPlainObject(obj))
return obj;
var res = {};
Object.keys(obj).forEach(function (key) {
var val = obj[key];
// use ref to proxy the property
if (!isRef(val)) {
val = createRef({
get: function () { return obj[key]; },
set: function (v) { return (obj[key] = v); },
});
}
// todo
res[key] = val;
});
return res;
}
isPlainObject
でオブジェクトかどうかを判別して、該当していた場合は渡されobj
をforEach
で回してgetter,setterを定義してやっているようです。
まとめ
最後までお読みいただきありがとうございます。
refとreactiveの違いについてざっくりと確認してきました。
ここまで触ってきての印象はref
で定義する変数は他と関連性が薄いもの、独立しているものが適しているように感じます。
かたやreactive
に関していうと、一つの変数の中にkey:value
の形でそれぞれが関連するものとして定義した方がいいものが適していると感じます。
例えばユーザーの情報など。
例:
const User = reactive({
name: 'Taro',
age: '19',
sex: 'male'
})
まだcompostionAPI自体ドキュメントが揃いきっているわけではないので、どのように運用していくのがいいのか、個人のプロダクトなどに突っ込んでいくことで判断していきたいと思います。