1.reactive を使用した際に、起こった問題
vue3
になって、オブジェクトを reactive
に入れるだけで、リアクティブになる。
vue2
では、Vue.set
を使うシーンがあったのに比べて、ひどくシンプルになって最高。
しかし、何も考えずに reactive
にしてはいけないパターンがある。
2.比較時の問題
Pure Object
とでもいうべき、reactive
でないオブジェクトと比べようとすると上手くいかない。
const foo = { bar: {} }
const foo2 = { baz: "hoge" }
const foo_reactive = reactive(foo)
foo.bar = foo2
foo_reactive.bar = foo2
console.log(foo.bar === foo2) /// true
console.log(foo_reactive.bar === foo2) /// false
console.log(foo.bar === foo_reactive.bar) /// false
普通に考えれば、reactive
を通したオブジェクトなので別の実体であることは明らか。
なのだが、外部JSON 等のデータから取得して reactive
なオブジェクトに格納した後で、
もとのデータと比較してしまうことがあり、 true
が帰ってこない謎がなかなか解けなかった。
foo_reactive.bar
というようにアクセスできてしまうのも、別オブジェクトである実感が持てず謎を呼ぶ要因となっているように思う。
(実際は、Proxy
オブジェクトになっている)
なので、isEqual
みたいなメソッドを作らざるを得なくなった。
大量の型の違うオブジェクトがあると、その度に作らないといけないのは非効率すぎる。
ここで重要なのは、それは reactive
でないといけないのか、ということである。
computed
でリアクティブ性が保たれるのであれば、reactive
にする必要性はない。
vue3
ではリアクティブ性に対する視点(必要か否か)での設計は、必要不可欠だ。
(当たり前の事だが実装を優先ぎみにすると忘れがちになりそう)
3.シリアライズ問題
IndexedDb
でユーザーの情報を保存しようとしたときに発覚した。
// IndexedDbについての記述は省略
// objectStore はオープンしたDBのオブジェクトストア
const foo = { bar: "hogehoge" }
objectStore.add(foo) // Ok
const foo_reactive = reactive(foo)
objectStore.add(foo_reactive) // Bad!!! #<Object> could not be cloned.
reactive
なオブジェクトをそのまま put
ないし add
してはいけない。
Proxy
オブジェクトになっているため、シリアライズできない。
じゃあ、Pure Object
に変換するメソッドを作るか・・・
という力技に出てはいけない。
オブジェクトの中にオブジェクトがあると、その中のオブジェクトもPure Object
に変換するメソッドが・・・となってしまう。
これも上記同様、computed
ですまないかを考える必要がある。
シリアライズできない問題は、IndexedDb
問わず多くありそうなので、こちらは忘れないようにしたい。