コード設計を学びたい人におすすめの本はこちら
記事をご覧いただきありがとうございます。
この記事では、Vue3の基礎である ref /reactive について詳しく解説します。
これらの概念を理解することで、Vueコンポーネント内でのリアクティブなデータを扱えるようになり、Vueの魅力を最大限に利用することができます。
英語で学習したい方はまずはこちらの記事をご覧ください。
英文の読み方について解説しています。
リアクティビティーとデータバインディング
リアクティビティー
Vue.js におけるリアクティビティーとは、データの変更を検知し、そのデータに関連する値を自動更新するメカニズムのことを指します。
英語で学ぶ
Reactivity in Vue.js refers ( to a mechanism [ that detects changes [ in data ] and automatically updates values [ related to that data. ]]) ( ① )
データバインディング
データバインディングは、データとUIの要素を連動させるメカニズムで、データの変更が即座に関連するUIに反映されるような仕組みを指します。
データバインディングとリアクティビティーの仕組みを使うことで、データの監視・変更を検知し、その値に紐づくデータやUIを自動的に更新することができます。
英語で学ぶ
Data binding is a mechanism [ that links data and UI elements ] ( so that < changes to the data > are immediately reflected ( in the associated UI. )) ( ② )
( By using data binding and reactivity mechanisms, ) you can monitor and detect data changes, and automatically update the data and UI associated [ with that value. ] ( ③ )
リアクティブな値
リアクティブな値は、データの変更を検知して自動的に更新される値を指します。
ref や reactive などの機能を使用して、変数やオブジェクトをリアクティブにすることができます。
これらのAPIを使うことで、データが変更されるとVue.jsがその変更を検知し、UIが自動的に再レンダリングされます。
英語で学ぶ
Reactive value refers ( to values [ that automatically update ] ( when < changes in data > are detected. )) ( ① )
( By using features [ such as ref or reactive in Vue.js, ]) it (仮主語) is possible ( to make variables and objects reactive. (真主語)) ( ② )
These APIs enable Vue.js < to detect modifications ( in the data, )> ( triggering an automatic re-rendering [ of the UI. ]) ( ⑤ )
Vue を使わないパターンと比較
let a = 1
let b = 2
let c = a + b
console.log(c) // 3
a = 2
console.log(c) // 3 のまま
// refを使用して変数をリアクティブに宣言
const a = ref(1);
const b = ref(2);
// cの計算をリアクティブに行う
const c = ref(a.value + b.value);
console.log(c.value); // 3
// aを更新
a.value = 2;
// cが値が再計算され、新しい値が表示される
console.log(c.value); // 4
リスニングする
ref とは
ref とはリアクティブな変数を扱うための関数です。
英語で学ぶ
Ref is a function [ for handling reactive variables. ] ( ② )
ref の定義方法
ref は以下のように定義されています。単一値を受け取り、内部値を示したプロパティ.valueを保持した Refオブジェクトを返します。refでリアクティブにした値は、.value プリパティを利用して値にアクセスします。
英語で学ぶ
Ref is defined ( as below. ) Ref takes one argument and < returns a Ref object [ that holds the property .value [ indicating the internal value. ]]> ( ③ ) < Values [ made reactive [ with ref ]]> is accessed ( using the .value property. ) ( -③ )
function ref<T>(value: T): Ref<UnwrapRef<T>>
interface Ref<T> {
value: T
}
ref関数を利用する際は、以下のように形式で ref 関数で値をラップします。
英語で学ぶ
( When using the ref function, ) you wrap the value ( as follows. ) ( ③ )
const name = ref("Taro")
ref を使ったサンプルコード
<template>
<div>
<p>Counter: {{ counter.value }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
// refを使用してリアクティブな値を宣言
const counter = ref(0);
// ボタンがクリックされた時にカウンターを増加
const increment = () => {
counter.value++;
};
</script>
この例では、ref
を使ってリアクティブな値 counter
を宣言しています。
<p>
タグ内で{{ counter.value }}
として変数を表示しています。ボタンがクリックされると、increment
関数が呼ばれ、counter
の値が増加します。Vue.jsがref
で変数をラップしているため、変更があると即座に関連する部分が再レンダリングされます。
英語で学ぶ
( In this example, ) ref is used ( to declare the reactive value counter. ) ( -③ )
( Inside the <p> tag, ) the variable is displayed ( as {{ counter.value }}. )
( When the button is clicked, ) the increment function is called, ( increasing the value [ of counter. ]) ( -③ ) ( As Vue.js wraps the variable [ with ref, ]) ( ③ ) any changes result ( in an immediate re-rendering [ of the associated parts. ]) ( ① )
リスニングする
reactive とは
reactive とは ref と同様リアクティブな変数を扱うための関数です。ref との違いについては次の章で説明します。
英語で学ぶ
Reactive is a function [ for handling reactive variable, ] [ similar to ref. ] ( ② ) < The difference [ from ref ]> will be explained ( in the next chapter. ) ( -③ )
reactive の定義方法
reactive は以下のように定義されています。オブジェクトを引数にとって、リアクティブなProxyオブジェクトを返します。
英語で学ぶ
Reactive is defined ( as follows. ) ( -③ ) It takes an object ( as an argument ) and returns a reactive Proxy object. ( ③ )
function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
reactive を使ったサンプルコード
<template>
<div>
<p>User: {{ user.name }}, Age: {{ user.age }}</p>
<button @click="updateAge">Increment Age</button>
</div>
</template>
<script setup>
import { reactive } from 'vue';
const userData = {
name: 'John',
age: 30,
};
// reactiveを使用してリアクティブなオブジェクトに変換
const user = reactive(userObj);
// ユーザーの年齢を更新する関数
const updateAge = () => {
user.age++;
};
</script>
このサンプルでは、reactive
を使用してuserData
オブジェクトをリアクティブなオブジェクトに変換しています。Vue.jsが提供するリアクティビティーシステムにより、userData
オブジェクト内のプロパティの変更が検知され、それに応じてUIが再レンダリングされます。
テンプレート内では{{ user.name }}
と{{ user.age }}
を使用してuser
オブジェクトのプロパティを表示しています。ボタンがクリックされるとupdateAge
関数が呼ばれ、user
オブジェクトのage
がインクリメントされ、その変更が即座にUIに反映されます。
英語で学ぶ
( In this example, ) reactive is used ( to transform the userData object ( into a reactive object. )) ( -③ ) < The reactivity system [ provided ( by Vue.js )]> detects < changes [ in the properties [ of the userData object, ]]> ( triggering a re-rendering [ of the UI accordingly. ]) ( ③ )
( Within the template, ) < {{ user.name }} and {{ user.age }} > are used ( to display the properties [ of the user object. ]) ( -③ ) ( When the button is clicked, ) the updateAge function is called, ( incrementing the age property [ of the user object. ]) ( -③ ) This change is immediately reflected ( in the UI due to Vue.js reactivity system. ) ( -③ )
リスニングする
ref / reactive の注意点
ref / reactive の注意点としては、分割代入するとリアクティブ性が失われる点です。
英語で学ぶ
< The caveat with ref and reactive > is < that ( when using destructuring assignment, ) reactivity is lost. > ( ② )
<template>
<div>
reactive {{ reactiveCount }}
ref {{ refCount }}
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue';
// リアクティブな値を定義
const counterReactive = reactive({
count: 1,
});
// 分割代入によってリアクティブでなくなる
let { count: reactiveCount } = counterReactive;
// refを使用してリアクティブな値を定義
const counterRef = ref({
count: 1,
});
// 分割代入によってリアクティブでなくなる
let { count: refCount } = counterRef.value;
const increment = () => {
reactiveCount++;
refCount++;
}
</script>
上記のコードでは、ref と reactive を使ってリアクティブなオブジェクトを定義し、分割代入でリアクティブな値を変数 reactiveCount
と refCount
に代入しています。
画面には、リアクティブな値を分割代入した変数 reactiveCount
とrefCount
を描画し、ボタンをクリックすることで値をインクリメントしています。
しかし、実際に動かしてみると、値は変わりません。
これは分割代入により、リアクティブな性質が失われたのが原因です。
このように、リアクティブな値は分割代入することでリアクティブな性質を失うため注意が必要です。リアクティブ性質を保持した値を代入したければ、次に紹介する toRef / toRefs を利用する必要があります。
英語で学ぶ
The above code uses ref and reactive ( to define a reactive object ) and uses destructuring assignment ( to assign reactive value ( to the variables reactiveCount and refCount. )) ( ③ )
( On the screen, ) This code draw the variables reactiveCount and refCount, [ which are divided and assigned reactive value, ] and increment the values ( by clicking the button. )( ③ )
However, ( when you actually run it, ) the value does not change. ( ① )
This is ( because the reactive property is lost ( due to destructuring assignment. )) ( ① )
( In this way, ) you must be careful ( because reactive value lose their reactive nature ( when destructuring them. )) ( ② ) ( If you want < to assign a value [ that retains the reactive nature, ]>) you need < to use toRef / toRefs, > [ which will be introduced next. ] ( ③ )
toRef / toRefs とは
- toRef… リアクティブなオブジェクトの単一のプロパティをRefオブジェクトに変換して返します。
英語で学ぶ
toRef… toRef converts a single property [ of a reactive object ] ( to a Ref object ) and returns it. ( ③ )
<script setup>
import { reactive, toRef } from 'vue';
// reactiveオブジェクトを作成
const userData = reactive({
name: 'John',
age: 25,
});
// toRefを使って単一のプロパティをリアクティブな値に変換
const nameRef = toRef(userData, 'name');
console.log(nameRef.value); // 'John'
</script>
- toRefs…リアクティブなオブジェクトの全てのプロパティをRefオブジェクトに変換して返します。
英語で学ぶ
toRefs… toRefs converts all properties [ of a reactive object ] ( to Ref objects ) and returns them. ( ③ )
<script setup>
import { reactive, toRef, toRefs } from 'vue';
// reactiveオブジェクトを作成
const userData = reactive({
name: 'John',
age: 25,
});
// toRefsを使って複数のプロパティを一度にリアクティブな値に変換
const { name, age } = toRefs(userData);
console.log(name.value); // 'John'
console.log(age.value); // 25
</script>
先ほど動かなかったサンプルコードも、toRefsを使うことでリアクティブな性質を持った値を利用できます。
英語で学ぶ
( Even in the sample code [ that did not work earlier, ]) you can use values [ with reactive nature ] ( by using toRefs. ) ( ③ )
<template>
<div>
// toRefsを使うことで、分割代入した変数もリアクティブな性質を保持しているため、
// ボタンをクリックするとVueが変更を検知し、画面が即座に更新されます。
reactive {{ reactiveCount }}
ref {{ refCount }}
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { ref, reactive, toRefs } from 'vue';
// リアクティブな値を定義
const counterReactive = reactive({
count: 1,
});
let { count: reactiveCount } = toRefs(counterReactive);
// refを使用してリアクティブな値を定義
const counterRef = ref({
count: 1,
});
let { count: refCount } = toRefs(counterRef.value);
const increment = () => {
reactiveCount.value++;
refCount.value++;
}
</script>
リスニングする
ref / reactive の違い
ref と reactive の違いは、扱えるデータが異なるということです。ref は主にプリミティブ型とオブジェクトを扱えるのに対して、reactive はオブジェクトのみをを扱えます。
英語で学ぶ
< The difference [ between ref and reactive ]> is < that they can handle different data. > ( ② ) Ref can mainly handle primitive types and objects, ( whereas reactive can only handle objects. ) ( ③ )
JavaScript primitive types are basic data types [ that are not objects. ] (Example: numbers, strings, boolean values, etc.) ( ② )
ref と reactive のオブジェクトの扱いの違い
ref を使ったリアクティブなオブジェクトにアクセスするには .value
プロパティを使用する必要があります。
英語で学ぶ
( To access reactive objects [ using refs, ]) you must use the .value property. ( ③ )
import { ref } from 'vue';
// オブジェクトを ref でラップ
const person = ref({ name: 'John', age: 25 });
// ref でラップされたオブジェクトのプロパティにアクセス
console.log(person.value.name); // 'John'
console.log(person.value.age); // 25
一方で、reactive でラップされたオブジェクトは、通常の JavaScript オブジェクトと同様に、直接プロパティにアクセスできます。
英語で学ぶ
( On the other hand, ) < objects [ wrapped in reactive ]> can access their properties directly, ( just like regular JavaScript objects. ) ( ③ )
import { reactive } from 'vue';
// オブジェクトを reactive でラップ
const person = reactive({ name: 'John', age: 25 });
// reactive でラップされたオブジェクトのプロパティに直接アクセス
console.log(person.name); // 'John'
console.log(person.age); // 25
リスニングする
ref / reactive の使い分けについては…あまりわかっていません!(公式ドキュメントを見ても使い分けについては詳しく言及されていませんでした)
以下の観点から、「基本的には ref を使う」でいいのかなと思っています。
・ref はプリミティブな値とオブジェクトを扱える(reactiveはプリミティブ型を扱えない)
・注意点として、.value を利用しないと値にアクセスできないが、逆に .value を利用することで、これはリアクティブな値を扱っているんだなと推測できる
使い分けについて詳しい方は教えていただけると幸いです。
※ 公式ドキュメントに以下のような記載があったので、決定的な使い分けは決まっていないそうです。
Ever since the introduction of the Composition API, one of the primary unresolved questions is the use of refs vs. reactive objects
https://vuejs.org/guide/extras/reactivity-transform.html
この記事で出てきた英語5選
- so that S V… → 「(目的)SVするように~する」 / 「(結果) ~なので、SVする」※ 結果の用法では”, so that”の形式で so that の前にカンマをとる
- S enable O to do… → [S]が[O]が〜するのを可能にする
- dut to ~… → ~が原因で、~に起因して、~のせいで
- transform A into B… → AをBに変える
- whereas… → 一方