21
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

リンクアンドモチベーションAdvent Calendar 2023

Day 5

Vue.jsのrefとreactiveを実コードで比較してみた

Last updated at Posted at 2023-12-04

初めに

本記事はリンクアンドモチベーション Advent Calendar 2023の5日目になります。

先日、弊社がプラチナスポンサーをしていたVue Fes 2023が開催されました。
私はブース運営で現地に赴き、実際に幾つかの講演も拝見する機会をいただきました。

その中の最後のセッションのVue.js クリニックにて、
「refとreactiveどちらをどう使い分ければいいの?」という質問があり、
聞いていて「なるほど!」ととても学びのある内容だったので、
これを機に実際に動かしながら当日エキスパートの方々が言っていた意味を更に深く理解しようと思います。

実際の質問とその回答

当日の質問とその回答を記載します。

image.png

  • ref
    • 基本はこちらを使うでいい
      • プリミティブ型で定義出来るからチームでコードを管理するのが楽
      • 最初は皆.valueを付けるのに慣れないと思ってたけど、今は皆慣れてるから
    • 一応、refは内部でreactiveを呼んでるとのこと(あとから調べてみた)
  • reactive
    • Vue2と書き方が似ていて移行しやすいと思ったから用意してた
    • 公式Documentにも最初はこっちが上に書いてあったらしい
    • 2つのオブジェクトで共通のステートを持っておきたいというときイミュータブルにしたい時に便利かもしれない
    • Vue3になってthisを付けなくてもアクセスできるから普通のオブジェクトと判別がしにくい

ということで、基本はref推しでした。ドキュメントに記載する順番の話とか面白いですね。
今日は実際にコードを書いてみて、エキスパートの発言の意味することをちゃんと理解しようと試みます。

理解するに当たって作るアプリ

簡単な出品アプリ。名前と価格を入れたら下に表示されるだけ。
image.png

ref

ref.vue
<template>
  <div>
    <h2>商品を出品する</h2>
    <form @submit.prevent="addProduct">
      <div>
        <label for="productName">商品名:</label>
        <input id="productName" :value="productName" @input="updateName">
      </div>
      <div>
        <label for="productPrice">価格:</label>
        <input id="productPrice" type="number" :value="productPrice" @input="updatePrice">
      </div>
      <button type="submit">商品を追加</button>
    </form>

    <h2>出品された商品</h2>
    <div v-for="product in products" :key="product.id">
      <h3>{{ product.name }}</h3>
      <p>価格: {{ product.price }}</p>
    </div>
  </div>
</template>

<script>
import { ref } from 'vue';

export default {
  setup() {
    const products = ref([]);
    const productName = ref('');
    const productPrice = ref(0);

    const updateName = (event) => {
      productName.value = event.target.value;
    };

    const updatePrice = (event) => {
      productPrice.value = parseFloat(event.target.value) || 0;
    };

    const addProduct = () => {
      if (productName.value && productPrice.value > 0) {
        products.value.push({
          id: Math.random(),
          name: productName.value,
          price: productPrice.value
        });
        productName.value = '';
        productPrice.value = 0;
      }
    };

    return { products, productName, productPrice, addProduct, updateName, updatePrice };
  }
};
</script>

reactive

reactive.vue
<template>
  <div>
    <h2>商品を出品する</h2>
    <form @submit.prevent="addProduct">
      <div>
        <label for="productName">商品名:</label>
        <input id="productName" :value="newProduct.name" @input="updateName">
      </div>
      <div>
        <label for="productPrice">価格:</label>
        <input id="productPrice" type="number" :value="newProduct.price" @input="updatePrice">
      </div>
      <button type="submit">商品を追加</button>
    </form>

    <h2>出品された商品</h2>
    <div v-for="product in products" :key="product.id">
      <h3>{{ product.name }}</h3>
      <p>価格: {{ product.price }}</p>
    </div>
  </div>
</template>

<script>
import { reactive } from 'vue';

export default {
  setup() {
    const products = reactive([]);

    const newProduct = reactive({
      name: '',
      price: 0
    });

    const updateName = (event) => {
      newProduct.name = event.target.value;
    };

    const updatePrice = (event) => {
      newProduct.price = parseFloat(event.target.value) || 0;
    };

    const addProduct = () => {
      if (newProduct.name && newProduct.price > 0) {
        products.push({
          id: Math.random(),
          name: newProduct.name,
          price: newProduct.price
        });
        newProduct.name = '';
        newProduct.price = 0;
      }
    };

    return { products, newProduct, addProduct, updateName, updatePrice };
  }
};
</script>

差分比較

template

ここは優位な差がなかった。
refはscript部分では.valueを付ける必要があるけど、
template部分では要らないからrefのデメリットがないからかな。

image.png

script

当たり前だけど、割と差分ありますね。
冒頭に述べたエキスパートの言ってたポイントを振り返りながら話してみると

  • ref
    • プリミティブ型で定義出来るからチームでコードを管理するのが楽
      • 影響が閉じられているので、変更を追いやすいなと感じました
    • 最初は皆.valueを付けるのに慣れないと思ってたけど、今は皆慣れてるから
      • 確かにもう見慣れた。リアクティブなことが分かるから良い
  • reactive
    • Vue3になってthisを付けなくてもアクセスできるから普通のオブジェクトと判別がしにくい
      • 確かに分かりにくい
    • 2つのオブジェクトで共通のステートを持っておきたいというときイミュータブルにしたい時に便利かもしれない
      • この程度だとやっぱりrefで良いじゃんってなりますね笑

image.png

終わりに

同じアプリをref/reactiveの別パターンで書いて比較して理解が深まった気がします。

21
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?