Vue.js ComputedとDataの違い オブジェクトを代入したときに元のオブジェクトへの影響の違い

Vue 2.5.17

ここのところ、Vueに取り組んで3か月強の私です。

Vueを書くときによく出てくる「Computed」と「Data」ですが、Computedは「算出プロパティです。」、Dataは「UIの状態となるデータのオブジェクトです。」という説明があります。

正直、この説明だと「なるほどね!理解した。」というには北海道と横浜ぐらい遠かったです。特に、Computedはキャッシュがあるとか、リアクティブではないデータの検知はしない、というのもよくわかりませんでした。(>_<)
そこで、いろいろ試してみました。特に、元のオブジェクトに対する影響、表示がどうやって更新されるか、ComputedとDataの違いについて調べています。

次のようなサンプルを作りました。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title></title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta name="robots" content="noindex, nofollow">
    <meta name="googlebot" content="noindex, nofollow">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://unpkg.com/vue@2.5.17"></script>

</head>
<body>
<div id="app">
    <p>【Data】{{ lancerEvolotionData.type }} {{ lancerEvolotionData.color }} <br>
        ドライバー:{{lancerEvolotionDriver()}}</p>
    <p>【Computed】{{ rx7Computed.type }} {{ rx7Computed.color }} <br>
        ドライバー:{{rx7Driver}}</p>
    <button @click="changeColorOfCar">車の色を変える</button>

</div>
<script>
    class Car {
        constructor(type, color) {
            this.type = type
            this.color = color
        }

        setColor(color) {
            this.color = color
        }
    }
    let lancerEvolotion = new Car('ランサーエボリューション', '白')
    let rx7 = new Car('RX7', '黄色')

      var vm = new Vue({
        el:'#app',
        data:{
            lancerEvolotionData: lancerEvolotion,
            lancerEvolotionDriver: function (){
                if(lancerEvolotion.color ==='白'){
                    return lancerEvolotion.color + 'は岩城清次'
                }else if(lancerEvolotion.color ==='黒'){
                    return lancerEvolotion.color + 'は須藤京一'
                }
            },
        },

        computed:{
            rx7Computed() {
                return rx7
            },
            rx7Driver() {
                if(this.rx7Computed.color ==='黄色'){
                    return this.rx7Computed.color + 'は高橋啓介'
                }else if(this.rx7Computed.color ==='白'){
                    return this.rx7Computed.color + 'は高橋涼介'
                }

            }
        },

        methods:{
            changeColorOfCar() {
                lancerEvolotion.setColor('黒')
                console.log(lancerEvolotion)
                console.log(this.lancerEvolotionData)
                console.log(this.lancerEvolotionDriver)

                rx7.setColor('白')
                console.log(rx7)
                console.log(this.rx7Computed)
                console.log(this.rx7Driver)

            }
        }
    })


</script>
</body>
</html>

内容は、まず最初にシンプルに車のオブジェクトがあります。

画面は次の通りです。


「ランサーエボリューション」という「白い車」と「RX7」という「黄色い車」があります。

ランサーエボリューション は主にVueの中ではDataで扱われ、RX7は主にComputedで扱われます。

それぞれ、車の色によりドライバーが変わります。

ランサーエボリューションの白 → 岩城清次
ランサーエボリューションの黒 → 須藤京一
この移り変わりは、Data→lancerEvolotionDriver で行っています。

RX7の黄色 → 高橋啓介
RX7の白 → 高橋涼介
この移り変わりは、Computed→rx7Driverで行っています。

というようになっています。(頭文字Dを知らない人にはわかりにくいネタで申し訳ありません。)

先程も書いたように、最初は次のような画面ですが

「車の色を変える」ボタンをクリックします。すると、次のようになります。

ランサーエボリューション(長い…変数名も長かった💦)は黒に変わり、ドライバー名も変わっているのに対して、RX7は白に変わりましたが、ドライバー名が変わっていません。

consoleを見てみますと次のようになっています。

Dataは何やら複雑なオブジェクトですね。

これ、一番最初のconsole.logで出力されている もともとのlancerEvolotion は

    let lancerEvolotion = new Car('ランサーエボリューション', '白')

で宣言したシンプルなオブジェクトのはずが、Vueに変換されて何やら複雑なオブジェクトになってますね。中身を展開してみると、次のようになっています。

そうでなければ、 オリジナルのオブジェクトである、lancerEvolotion の変化をVueが感知することができませんもんね。
これが、リアクティブってことなんですね!!(しゅごい)

一方のComputedに代入されたrx7のほうはなんの変化もありません。

最初に作った

let rx7 = new Car('RX7', '黄色')

と同じ、シンプルなオブジェクトです。また、computedのrx7DriverをConsoleで見ると、

 
黄色は高橋啓介

というシンプルな文字列が入っています。( ˊᵕˋ )

「え?そしたらComputedってなんなん?よく、文房具の数とか単価とかを入力していくらか計算するやつあるじゃん。」

となると思います。

これ、Computedが参照するデータがリアクティブであれば、Computedがリアクティブに計算してくれるようです。

試しに、さっきのコードのrx7をComputedからDataに移します。

//★変更ポイント(⋈◍>◡<◍)。✧♡

って書いてあるところだけが変更ポイントです。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title></title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta name="robots" content="noindex, nofollow">
    <meta name="googlebot" content="noindex, nofollow">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://unpkg.com/vue@2.5.17"></script>

</head>
<body>
<div id="app">
    <p>【Data】{{ lancerEvolotionData.type }} {{ lancerEvolotionData.color }} <br>
        ドライバー:{{lancerEvolotionDriver()}}</p>
    <p>【Computed】{{ rx7Data.type }} {{ rx7Data.color }} <br>
        ドライバー:{{rx7Driver}}</p>
    <button @click="changeColorOfCar">車の色を変える</button>

</div>
<script>
    class Car {
        constructor(type, color) {
            this.type = type
            this.color = color
        }

        setColor(color) {
            this.color = color
        }
    }
    let lancerEvolotion = new Car('ランサーエボリューション', '白')
    let rx7 = new Car('RX7', '黄色')

    var vm = new Vue({
        el:'#app',
        data:{
            lancerEvolotionData: lancerEvolotion,
            lancerEvolotionDriver: function (){
                if(lancerEvolotion.color ==='白'){
                    return lancerEvolotion.color + 'は岩城清次'
                }else if(lancerEvolotion.color ==='黒'){
                    return lancerEvolotion.color + 'は須藤京一'
                }
            },
            rx7Data:rx7 //★変更ポイント(⋈◍>◡<◍)。✧♡
        },

        computed:{
            rx7Driver() {
                if(this.rx7Data.color ==='黄色'){ //★変更ポイント(⋈◍>◡<◍)。✧♡
                    return this.rx7Data.color + 'は高橋啓介' //★変更ポイント(⋈◍>◡<◍)。✧♡
                }else if(this.rx7Data.color ==='白'){ //★変更ポイント(⋈◍>◡<◍)。✧♡
                    return this.rx7Data.color + 'は高橋涼介' //★変更ポイント(⋈◍>◡<◍)。✧♡
                }
            }
        },

        methods:{
            changeColorOfCar() {
                lancerEvolotion.setColor('黒')
                console.log(lancerEvolotion)
                console.log(this.lancerEvolotionData)
                console.log(this.lancerEvolotionDriver)

                rx7.setColor('白')
                console.log(rx7)
                console.log(this.rx7Data)
                console.log(this.rx7Driver)

            }
        }
    })


</script>
</body>
</html>

すると「車の色を変える」ボタンをクリックした後の動作が次のように変わります。

ちゃんと、RX7の白に乗っているのは高橋涼介、と表示されました!!!

パチパチ。


以下は余談ですが、色々とほかにもわかったことがあって、最初に紹介したコードの

lancerEvolotion.setColor('黒')


をコメントアウトしてみると、そもそもボタンをクリックしても何も起こりません。Console.logで出力されるオリジナルのオブジェクトの中身もComputedの中身も変わってはいますが、画面が更新されません。
Dataはリアクティブなので、画面の更新をしてくれますが、Computedだけ更新しても、画面の更新はしてくれないのです。
Dataを更新すると、画面の更新をしてくれるので、Computedも新しい値でついでに表示の更新がされる、という仕組みのようです。

<参考>

リアクティブの探求 Vue2

リアクティブの探求 Vue3 Vue2のドキュメントよりわかりやすい

Computed Properties

S課長のオーリス。若き日は峠を攻めてたとかいないとか。
S課長のオーリス。若き日は峠を攻めてたとかいないとか。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です