
ref・reactiveと2つ方法が用意されていると迷ってしまいますよね。
またref・reactiveにはそれぞれ使う際の注意点もあります。
この記事ではrefとreactiveの使い方や違い、注意するべき点などを解説していきます。
refとは
refはthisへのアクセスに依存せずにリアクティブな変数を扱うためにComposition APIで導入された新しい概念です。
ref関数を用いてリアクティブな変数を定義することができます。
refの定義

function ref<T>(value: T): Ref<T>
値を1つ受け取り、リアクティブなRef<T>型のオブジェクトを返します。
refには例えば以下のようになんでも渡すことができます。
- オブジェクト
- 配列
- プリミティブ
というのも、内部ではrefに渡された値がオブジェクトだった場合には以下のようにreactive(後述)が呼ばれています。
const convert = (val) => isObject(val) ? reactive(val) : val;
isObjectは以下のように定義されています。
const isObject = (val) => val !== null && typeof val === 'object';
refの使い方

const countRef = ref(1);
const doubleCount = computed(() => {
return countRef.value * 2;
});
- refで定義したリアクティブな変数の値にアクセスするには.valueを使用します
refの欠点
ここまでrefの定義・使い方を見てきましたが、refには以下のような欠点があると公式ドキュメントで言及されています。
1.When using the Composition API, we will need to constantly distinguish refs from plain values and objects, increasing the mental burden when working with the API.
2.Reading and mutating refs are more verbose than working with plain values due to the need for .value.
翻訳すると以下のような感じです。
1.Composition APIを使う際には常にrefなのかプレーンな値またはオブジェクトなのか区別する必要があります。
これによって精神的な負担が増えます。2.プレーンな値と違ってrefは.valueを用いて値にアクセスする必要があるため、より冗長です。
1つ目の欠点に関しては変数名の接尾辞にRefを付けるなどして回避することが公式ドキュメントで推奨されています。
またComposition APIではコードの可読性・再利用性の向上のために、小さな関数にロジックを分離することが簡単にできるようになっています。
これによってrefのオーバーヘッドが管理可能なものになるということも言及されています。
The mental burden can be greatly reduced by using a naming convention (e.g. suffixing all ref variables as xxxRef), or by using a type system.
On the other hand, due to the improved flexibility in code organization, component logic will more often be isolated into small functions where the local context is simple and the overhead of refs are easily manageable.
翻訳すると以下のような感じです。
この精神的負担は命名規則または型システムを使うことで軽減できます。
その他に、コードの柔軟性のためのコンポーネントロジックがローカルコンテキストが単純な小さな関数に分割されることになるので、このrefの精神的負担は管理可能なものになります。
refを使用する際には以下の点に注意しておきましょう。
- refで定義したリアクティブな変数の値にアクセスするには.valueを使用する
- 変数名の接尾辞にRefを付けるなどの命名規則を導入する
- コンポーネントのロジックを小さな関数に分割する
reactiveとは
reactiveはVue2のVue.observable()と同じものです。
reactiveの定義

function reactive<T extends object>(raw: T): T
プリミティブ以外の値を受け取り、リアクティブなオブジェクトに変換してくれます。
公式ドキュメントでは以下のようにオブジェクトのみを渡すように言及されています。
Takes an object and returns a reactive proxy of the original.
翻訳すると以下のような感じです。
オブジェクトを引数にとりそのオブジェクトのリアクティブなプロキシを返します。
reactiveにプリミティブを渡すと以下のような警告がconsoleに出力され、リアクティブな変数の生成に失敗します。
value cannot be made reactive:
reactiveの使い方

const obj = reactive({
count: 1,
});
const doubleCount = computed(() => {
return obj.count * 2;
});
以下のようにネストされたオブジェクトもリアクティブになります。
const obj = reactive({
nested: {
count: 1,
},
});
const doubleCount = computed(() => {
return obj.nested.count * 2;
});
reactiveの注意点
reactiveを使用する際にはリアクティビティの消失に注意する必要があります。
例えば以下のようにreactiveで生成したオブジェクトに分割代入を適用して得た変数はリアクティブではなくなっています。

const obj = reactive({
count: 1,
});
// countはリアクティブではありません!!
const { count } = obj;
// obj.countが変更されても反応しません!!
const doubleCount = computed(() => {
return count * 2;
});
同様にスプレッド構文を使用してもリアクティビティが失われてしまうため注意が必要です。
- reactiveで生成した変数には分割代入を使用しない
- reactiveで生成した変数にはスプレッド構文を使用しない
Ref vs. Reactive

refとreactiveの違い
refとreactiveの違いについては、公式ドキュメントでは以下のように言及されています。
The difference between using ref and reactive can be somewhat compared to how you would write standard JavaScript logic.
翻訳すると以下のような感じです。
refとreactiveの違いは、標準のJavaScriptロジックを作成する方法と多少比較できます。
さらに公式ドキュメントではコード例と共に補足説明がされていますが、結局refとreactiveの違いはJavaScriptでプリミティブを使うかオブジェクトを使うか程度の違いしかないようです。
ここまで見てきたrefとreactiveの使い方や注意点を理解していれば、違いについてはそれほど考えなくても良いでしょう。
refとreactiveの使い分け
refとreactiveの使い分けについては、公式ドキュメントで以下のように言及されています。
Understandably, users may get confused regarding which to use between ref and reactive.
First thing to know is that you will need to understand both to efficiently make use of the Composition API.
Using one exclusively will most likely lead to esoteric workarounds or reinvented wheels.
翻訳すると以下のような感じです。
当然の事ながらユーザはrefとreactiveのどちらを使うべきか困惑するでしょう。
まず最初に知っておくべきことはComposition APIを効率的に使用するためには両方を理解する必要があります。
もしrefかreactiveのどちらか片方だけを使用すると、難解な回避策やホイールの再発明を招く可能性があります。
refとreactiveの両方を理解して使い分けるように言及されていますが、実はこのrefとreactiveの使い分け方を決めるのは時期尚早であるとも公式ドキュメントで言及されています。
現時点では使い分け方が策定中で、世界中からのフィードバックを踏まえてこれからベストプラクティスが決められるようです。
At this stage, we believe it is too early to mandate a best practice on ref vs. reactive.
We will be collecting real world user feedback and eventually provide more definitive guidance on this topic.
翻訳すると以下のような感じです。
現段階ではrefとreactiveのベストプラクティスを決めるのは時期尚早です。
世界中からのフィードバックを踏まえて最終的にはベストプラクティスを作成して提供します。

使い分けのベストプラクティスは策定されていませんが、公式ドキュメントの中では2つの手法が推奨されています。
ベストプラクティスが策定されるまでは以下の2つから好きな方を選んで使のが良いようです。
1. Use ref and reactive just like how you’d declare primitive type variables and object variables in normal JavaScript.
It is recommended to use a type system with IDE support when using this style.2.Use reactive whenever you can, and remember to use toRefs when returning reactive objects from composition functions.
This reduces the mental overhead of refs but does not eliminate the need to be familiar with the concept.
翻訳すると以下のような感じです。
1.プリミティブにはref、オブジェクトにはreactiveを使用する。
このスタイルを採用する場合にはIDEの型サポートを使用して型システムを利用することを推奨します。2.可能な限り、いつでもreactiveを使用する。
このスタイルを採用する場合には、合成関数からオブジェクトを返す場合にtoRefsを使用してください。
またこのスタイルは、refsの精神的なオーバーヘッドを軽減しますが、refsの概念に精通することは必要です。

refとreactiveについては策定中という雰囲気が伝わってきますね。

もし2のスタイルを採用する場合は、reactiveの注意点の章でも見たようにリアクティビティの消失に注意する必要があります。
この解決策として先ほど引用した中ではtoRefsを使用するように言及されていました。
toRefsとは
toRefsはreactiveで生成したオブジェクトの各プロパティをrefに変換してくれます。
このtoRefsを使えば以下のように分割代入やスプレッド構文を適用しても、それぞれのプロパティがrefになっているので、リアクティビティが保たれます。
const obj = toRefs(
reactive({
count: 1,
})
);
// countはrefに変換されています
const { count } = obj;
// countが変更されると反応します
const doubleCount = computed(() => {
return count.value * 2;
});

合成関数については以下の記事で解説していますので、気になる方は是非ご覧ください。
2020年9月18日に「Vue.js v3.0」がリリースされ、その中でも特にVue Composition APIが注目されています。 Composition APIの使い方が分かったあとは、なぜ使うのかというところが気になりますよね。[…]
まとめ
この記事ではrefとreactiveについて解説してきました。
refとreactiveの使い分け方が策定されるまでは、それぞれの注意点に気を付けつつ、個人やプロジェクトの好みに応じたスタイルで使いこなしていきたいですね。
それでは、ここまでご覧いただきありがとうございました。