フロントエンド

【Vue3】リアクティブとは?refやcomputed(算出プロパティ)

Vue3リアクティブ

reisuta

Webエンジニア | 20代中盤 | 大学時代はGmailすら知らないIT音痴でプログラミングとは無縁の生活を送る → 独学でプログラミングを学ぶ → Web系受託開発企業にエンジニアとして就職 → Web系自社サービス企業に転職 | 実務未経験の頃からVimを愛好しており、仕事でもプライベートでも開発はVimとTmuxを使っているので、VSCodeに疎いのが最近の悩み。何だかんだでやっぱりRubyが好き。

本記事では、Vue.jsの重要な概念である、
リアクティブについて扱います。

その中でも、refやcomputedについて、
詳細に解説します。

動画でご覧になりたい方は、
こちらをご参考ください。

リアクティブとは?

リアクティブとは何でしょうか?
私も最初、この概念がよくわかりませんでした。

記事とかドキュメントを見ても、
いまいちピンと来ませんでした。

リアクティブとは、簡単に言うと、
変数の値が変化すると、view側もそれに応じて変わってくれる流れみたいないものです。

これは、双方向データバインディングを想起するとイメージしやすいと思いますが、
JS → HTML、HTML → JSのように、変更に応じて、
一方に反映させていくような感じですね。

大抵の場合、変数はJS側で定義し、
view側はHTMLになるので、
本質的には、双方向データバインディングの議論と
あまり変わらないかなと思います。
(双方向データバインディングについては、こちらの記事をご参考ください。)

具体的には、下記あたりがそれに該当しますかね。

  • ref()
  • reactive()
  • computed()

あとは、JavaScriptプロキシとかも該当するのかもしれません
(混乱するだけだから、特に意識しなくてもいいような気もしますが...)

リアクティブの厳密な定義としては、
変更がview側に検知されて、view側を気にしなくていいメリットがあるみたいな感じだと思いますが、
Vue.jsにおけるリアクティブといったら、ほぼほぼ、
ref()のことを言っていると思っても大丈夫だと思います。

同じ種類として、reactive()というのもありますが、
ぶっちゃけ使う頻度は、ref()よりは下がると思います。

computed()も、リアクティブといえば、
リアクティブなのですが、
それよりは算出プロパティという、
関数としての特徴のほうが印象的な気がします。
(算出プロパティはリアクティブな依存関係にもとづきキャッシュされるので、
そういった意味では、リアクティブの関数verみたいな感じですが)

https://ja.vuejs.org/guide/essentials/computed.html

ref

さて、それでは主役のrefとは一体何でしょうか?

まず、リアクティブな変数を作成するには、
ref以外にも、reactive()というのもあります。

https://ja.vuejs.org/guide/essentials/reactivity-fundamentals.html

ただ、reactive()は、オブジェクト型にしか使えないため、
文字列とか数値みたいなプリミティブ型には使えないという制限があります。

プリミティブ型って何?という方は、
下記の記事をご参考ください。

TypeScriptプリミティブ型
参考【TypeScript基礎】プリミティブ型、基本的な型の種類について

TypeScriptの特徴は何と言っても、型にありますが、そんな型の中でも、中心的な役割を占める、プリミティブ型について、詳しく解説します。 文字ではなく、動画で観たい方は、下記をご参考ください。 h ...

続きを見る

その制限に対処したのが、
ref()という感じです。

そのため、refでリアクティブな変数を作成し、
プリミティブ型にも対処できるという感じですね。

例えば、

<template>
  <div>
    <input type="text" ref="inputRef">
    <button @click="handleClick">ボタン</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const inputRef = ref<HTMLInputElement>();

function handleClick() {
  if (inputRef.value) {
    console.log(inputRef.value.value);
  }
}
</script>

こんな感じのコードがあるとすると、
inputRefという変数がリアクティブになっているので、
inputタグの中身が変われば、
変数の中身も変わっていき、ボタンをクリックすると、
その変わった変数の中身を出力しているといった感じですね。

基本的には、こんな感じで、
HTMLのフォームとかの値をTypeScriptの変数の方にも反映させたいときに、
refとか、v-modelを使用することになるでしょう。

リアクティブじゃないとどうなる?

リアクティブじゃないコードのサンプルを紹介します。

<template>
  <div>
    <p>商品価格: {{ price }}円</p>
    <p>消費税込み価格: {{ priceIncludingTax }}円</p>
    <button @click="handleClick">ボタン</button>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue';

let price = 1000

const priceIncludingTax = computed(() => {
  const taxRate = 0.1;
  return Math.round(price * (1 + taxRate));
});
function handleClick() {
  price += 100
  console.log(price)
}
</script>

この場合、Typescript側の変数priceの中身と、
html(view側)で表示されている値が食い違っています。

画面に描写されているのは、
初期値の、1000と1100ですが、
console.logでは、ちゃんと100づつ加算されている、
変数priceが出力されています。

リアクティブな場合と比べてみます。
※変数名が手抜きなのは許してください

<template>
  <div>
    <p>商品価格: {{ price }}円</p>
    <p>ref商品価格: {{ refprice }}円</p>
    <p>消費税込み価格: {{ priceIncludingTax }}円</p>
    <p>ref消費税込み価格: {{ refpriceIncludingTax }}円</p>
    <button @click="handleClick">ボタン</button>
    <button @click="refClick">リアクティブボタン</button>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue';

let price = 1000
const refprice = ref(1000)

const priceIncludingTax = computed(() => {
  const taxRate = 0.1;
  return Math.round(price * (1 + taxRate));
});

const refpriceIncludingTax = computed(() => {
  const taxRate = 0.1;
  return Math.round(refprice.value * (1 + taxRate));
});

function handleClick() {
  price += 100
  console.log(price)
}

function refClick() {
  refprice.value += 100
  console.log(refprice.value)
}
</script>

この場合、リアクティブの方は、
加算されるに従って、画面も反映されていますね。

computed(算出プロパティ)

上記で少し登場しましたが、
computedは、さっきのコードで言うと、

import { ref, computed } from 'vue';

const priceIncludingTax = computed(() => {
  const taxRate = 0.1;
  return Math.round(price * (1 + taxRate));
});

const refpriceIncludingTax = computed(() => {
  const taxRate = 0.1;
  return Math.round(refprice.value * (1 + taxRate));
});

ここの部分です。
Vue3 Composition APIの場合、importして使用します。

構文的には、computed()の中に、関数処理を書いていく感じです。
基本的には、複雑なロジックを関数として、
htmlの方に表示するために使われるので、
{{}}構文の中に複雑なロジックを書かないための改善策みたいな感じです。

computed()は、普通の関数としても実装はできますが、
少し違いがあります。

<template>
  <div>
    <p>ref商品価格: {{ refprice }}円</p>
    <p>ref消費税込み価格: {{ refpriceIncludingTax }}円</p>
    <p>普通の関数: {{ func1() }}</p>
    <button @click="refClick">リアクティブボタン</button>
    <button @click="refClick2">リアクティブボタン22</button>
    <p>{{ omake }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue';

const refprice = ref(1000)
const omake = ref(10)

const func1 = () => {
  console.log('普通の関数の処理')
  const taxRate = 0.1;
  return Math.round(refprice.value * (1 + taxRate));
}

const refpriceIncludingTax = computed(() => {
  console.log('computedの処理')
  const taxRate = 0.1;
  return Math.round(refprice.value * (1 + taxRate));
});

function refClick() {
  refprice.value += 100
  console.log(refprice.value)
}

function refClick2() {
  omake.value += 10
}
</script>

computedは、中のリアクティブな変数の値が更新された際にだけ、
呼ばれるのに対し、普通の関数は、再描画が起きると毎回呼ばれます。

つまり、computedのほうが、リアクティブなキャッシュを保持しているといった感じです。

上記のコードの場合、
リアクティブボタンを押すと、
computedが感知している、リアクティブなrefprice関数が書き換わるので、
処理が呼ばれますが、自身が感知していない、omake変数がリアクティブ22ボタンで書き換わっても、
computedの方は呼ばれないといった感じです。

まあ、正直この違いをクリティカルに利用したいユースケースは、
そんなにない気がしますが...笑

computedと普通の関数の違いとしては、
このような感じです。

  • この記事を書いた人
  • 最新記事

reisuta

Webエンジニア | 20代中盤 | 大学時代はGmailすら知らないIT音痴でプログラミングとは無縁の生活を送る → 独学でプログラミングを学ぶ → Web系受託開発企業にエンジニアとして就職 → Web系自社サービス企業に転職 | 実務未経験の頃からVimを愛好しており、仕事でもプライベートでも開発はVimとTmuxを使っているので、VSCodeに疎いのが最近の悩み。何だかんだでやっぱりRubyが好き。

おすすめ記事はこちら

Vim/Neovimプラグイン 1

プラグインをどれだけ入れるかは、その人の思想なども関係するので、一概にこれがいいというのはないかもしれません。 プラグインを全く入れない人もいれば、100個以上入れる人もいます。 ただそれでも、これだ ...

VimとNeovimの比較 2

本記事では、VimとNeovimの違いについて、解説します。 VimとNeovimの違いについては、普段頻繁にVimなどを使う方でなければ、正直、あまり気にしなくてもいいかなと思います。 ただ、Vim ...

Ruby変数やすべてがオブジェクトについて 3

本記事は、Rubyの基礎文法である、変数や真偽値、論理演算子に触れると同時に、「すべてがオブジェクト」というRubyの特徴的な思想についても解説します。 この思想は、Rubyの文法の根幹になっているの ...

4

エンジニアにおすすめの技術書 書籍学習は、エンジニアの嗜みみたいなところがありますが、 良書というものは、意外とそこまで多くもありません。 そこで本記事では「技術書マニアの筆者が厳選した技術書20選」 ...

5

エンジニアになるには? プログラミングは、専門性が高く自分一人で勉強するのが大変に感じることも多いですよね。 そこで本記事では「おすすめのプログラミングスクール5選」を特徴と、現役エンジニア目線で優れ ...

-フロントエンド