12k
All articles

Vue.jsにおけるComputed PropertiesとWatchersの仕組み

Vue 3のcomputed propertiesとwatchersの違いを解説。キャッシュ、リアクティビティ、副作用の観点から適切な使い分けを説明する。

OpenReplay Team
OpenReplay Team
Vue.jsにおけるComputed PropertiesとWatchersの仕組み

Vueのリアクティビティシステムは、依存関係を自動的に追跡し、データが変更されるとUIを更新します。しかし、Vue 3のcomputed propertiesVue 3のwatchersをいつ使うべきかを理解することが、クリーンでパフォーマンスの高いコードと保守の悪夢を分ける鍵となります。これらの機能がどのように動作し、それぞれがどのような場面で力を発揮するのかを探っていきましょう。

重要なポイント

  • Computed propertiesはキャッシュされる宣言的な関数で、リアクティブデータから新しい値を導出します
  • Watchersは副作用(API呼び出しなど)を処理し、非同期操作に最適です
  • 純粋な変換にはcomputedを、副作用を伴う命令的なロジックにはwatchersを使用します
  • Computed propertiesは依存関係が変更された場合のみ再計算され、パフォーマンスが向上します

Vueのリアクティビティの基礎を理解する

Vue 3のリアクティビティシステムは、Proxyを使用してプロパティがアクセスされたり変更されたりするタイミングを追跡します。リアクティブデータが変更されると、Vueはそのデータに依存するアプリケーションの部分を正確に把握し、効率的に更新します。Computed propertiesとwatchersは、この基盤の上に構築された2つの強力なツールで、それぞれがリアクティブワークフローにおいて異なる目的を果たします。

Vue 3のComputed Properties:宣言的でキャッシュされる

Computed propertiesは、既存のデータから新しいリアクティブな値を導出します。これらは宣言的で、キャッシュされ、常に副作用のない純粋関数であるべきです。

Composition APIの構文

<script setup>
import { ref, computed } from 'vue'

const price = ref(100)
const quantity = ref(2)

const total = computed(() => price.value * quantity.value)
const formattedTotal = computed(() => `$${total.value.toFixed(2)}`)
</script>

<template>
  <p>Total: {{ formattedTotal }}</p>
</template>

Options APIの構文

export default {
  data() {
    return {
      price: 100,
      quantity: 2
    }
  },
  computed: {
    total() {
      return this.price * this.quantity
    },
    formattedTotal() {
      return `$${this.total.toFixed(2)}`
    }
  }
}

最大の利点はキャッシュです。Vueは依存関係が変更された場合にのみcomputed propertyを再計算します。テンプレート内でformattedTotalを複数回参照しても、計算は更新サイクルごとに1回実行されるだけで、アクセスごとには実行されません。

書き込み可能なComputed Properties

時には、getterとsetterの両方を持つcomputed propertyが必要になることがあります:

import { ref, computed } from 'vue'

const firstName = ref('John')
const lastName = ref('Doe')

const fullName = computed({
  get() {
    return `${firstName.value} ${lastName.value}`
  },
  set(newValue) {
    [firstName.value, lastName.value] = newValue.split(' ')
  }
})

Vue 3のWatchers:命令的な副作用

Watchersはリアクティブな値を監視し、値が変更されたときに副作用を実行します。Computed propertiesとは異なり、watchersは命令的で、非同期操作、API呼び出し、DOM操作に最適です。

基本的なWatch構文

// Composition API
import { ref, watch } from 'vue'

const searchQuery = ref('')
const results = ref([])

watch(searchQuery, async (newQuery) => {
  if (newQuery.length > 2) {
    results.value = await fetchSearchResults(newQuery)
  }
})

自動追跡のためのwatchEffect

watchEffectは、明示的に宣言することなく依存関係を自動的に追跡します:

import { ref, watchEffect } from 'vue'

const searchQuery = ref('')
const results = ref([])

watchEffect(async () => {
  // searchQuery.valueを自動的に追跡
  if (searchQuery.value.length > 2) {
    results.value = await fetchSearchResults(searchQuery.value)
  }
})

高度なWatcherオプション

watch(source, callback, {
  immediate: true,  // 作成時に即座に実行
  deep: true,       // ネストされたプロパティを監視
  flush: 'post'     // DOM更新後に実行
})

ComputedとWatch:適切な選択をする

それぞれのアプローチをいつ使用するかは以下の通りです:

Computed Propertiesを使用する場合:

  • 既存のリアクティブデータから新しい値を導出する
  • テンプレートで結果が必要
  • 操作が同期的で純粋
  • 自動キャッシュが必要

Watchersを使用する場合:

  • 副作用を実行する(API呼び出し、ログ記録、localStorage)
  • 命令的なロジックでデータの変更に反応する
  • 非同期操作を処理する
  • 古い値と新しい値の両方にアクセスする必要がある

実践的な比較

// ❌ 誤り: computedでの副作用
const searchResults = computed(async () => {
  const response = await fetch(`/api/search?q=${query.value}`)
  return response.json() // 動作しません - computedは同期的である必要があります
})

// ✅ 正しい: 副作用にはwatcherを使用
watch(query, async (newQuery) => {
  const response = await fetch(`/api/search?q=${newQuery}`)
  searchResults.value = await response.json()
})

// ✅ 正しい: 純粋な導出にはcomputedを使用
const filteredResults = computed(() => 
  searchResults.value.filter(item => item.active)
)

パフォーマンスに関する考慮事項

Computed propertiesはキャッシュによってパフォーマンスに優れています。依存関係が変更された場合にのみ再計算されるため、高コストな操作に最適です:

// itemsまたはfilterTextが変更された場合にのみ再計算されます
const expensiveFilter = computed(() => {
  console.log('Filtering...') // 依存関係の変更時にのみ実行
  return items.value.filter(item => 
    complexFilterLogic(item, filterText.value)
  )
})

一方、watchersはトリガーされると常に実行されます。特に大きなオブジェクトに対してdeep: trueを使用する場合は、慎重に使用してください。

まとめ

Vue 3のcomputed propertieswatchersは、Vueのリアクティビティシステムの基礎であり続けています。シンプルなルールを覚えておきましょう:純粋でキャッシュされた導出にはcomputedを、副作用にはwatchersを使用します。Computed propertiesは自動キャッシュによってテンプレートをクリーンでパフォーマンスの高いものに保ち、watchersはcomputed propertiesでは処理できない命令的で非同期的な操作を処理します。両方をマスターすれば、エレガントで効率的なVueアプリケーションを書くことができるでしょう。

よくある質問

Computed propertyの中でasync/awaitを使用できますか?

いいえ、computed propertiesは同期的である必要があり、即座に値を返す必要があります。非同期操作には、watchersまたはmethodsを使用してください。Computed propertiesはリアクティブデータの純粋な変換のために設計されています。

watchEffectとwatchはいつ使い分けるべきですか?

自動的な依存関係追跡が必要で、古い値が不要な場合はwatchEffectを使用します。監視対象を明示的に制御したい場合、古い値へのアクセスが必要な場合、またはdeep watchingなどの特定の設定オプションが必要な場合はwatchを使用します。

Computed propertiesは配列やオブジェクトでも動作しますか?

はい、computed propertiesは配列やオブジェクトへの変更を追跡します。ただし、ネストされたプロパティの深いリアクティビティについては、ソースデータがrefまたはreactiveを使用して適切にリアクティブにされていることを確認してください。Vue 3はVue 2よりもこれをうまく処理します。

テンプレートで複数回使用された場合、computed propertyは何回再計算されますか?

Computed propertyは、参照される回数に関係なく、レンダリングサイクルごとに1回だけ計算されます。このキャッシュ動作により、複数の場所で使用される高コストな計算に対してcomputed propertiesが効率的になります。

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.