🐈

Vue3でリアクティブ値を含むオブジェクトをrefでラップしたら内部の型が変わってハマった

2023/05/26に公開

問題

以下のようなリアクティブ値を含むオブジェクトをrefでラップした時にcomputedの型が消えてしまいハマりました。

import { ref } from "vue"
const three = ref(3)
const object = {
  one: 1,
  two: 2,
  three: computed(() => {
    return three.value
  }),
}
const objectRef = ref(object)
objectRef.value = object // ここで型エラー



なぜ型が変わったのか?

公式にこんな一文があります。

If an object is assigned as a ref's value, the object is made deeply reactive with reactive(). This also means if the object contains nested refs, they will be deeply unwrapped.

DeepLで和訳するとこんな感じ。

オブジェクトがrefの値として割り当てられた場合、そのオブジェクトはreactive()でディープリアクティブにされます。これは、オブジェクトがネストしたrefを含んでいる場合、それらが深くアンラップされることも意味します。

refでオブジェクトをラップすると、オブジェクト内に含まれるrefが解除されてしまい、オブジェクト全体がリアクティブ化されてしまうらしい。
全体をリアクティブ化せずにvideo.valueのみをリアクティブ化するには、shallowRefを使えとの事。

なのでshallowRefを使用して以下のように修正します。

import { ref } from "vue"
const three = ref(3)
const object = {
  one: 1,
  two: 2,
  three: computed(() => {
    return three.value
  })
}
- const objectRef = ref(object)
+ const objectRef = shallowRef(object)

これでOK。

おわりに

雰囲気でrefを使っていたせいでハマってしまいました・・・・・
公式ドキュメントはちゃんと読みましょう・・・・

GitHubで編集を提案

Discussion