Vue 3 如何在响应式对象上使用 watch 或 watchEffect (和 console.log)?

Hen*_*Jan 6 javascript watch vue-reactivity vuejs3 vue-composition-api

我试图(深入)观察 Vue 3 中响应式对象的任何变化:

\n
import { reactive, watchEffect } from \'vue\';\n\nconst settings = reactive({\n  panes: {\n    left: {\n      defaultAction: "openInOtherPane",\n    },\n    right: {\n      defaultAction: "openInThisPane",\n    },\n  },\n  showMenu: false,\n  isDrawerOpen: false,\n});\n\nwatchEffect(() => {\n  console.log(\'The new settings are\', settings);\n});\n\n// Try to change a setting (this does not trigger watchEffect)\nsettings.panes.left.defaultAction = "none";\n
Run Code Online (Sandbox Code Playgroud)\n

这段代码有两个问题:

\n
    \n
  • 设置更改时不会触发 watchEffect
  • \n
  • console.log 以以下形式显示不可读的对象Proxy { <target>: {\xe2\x80\xa6}, <handler>: {\xe2\x80\xa6} }
  • \n
\n

我也尝试过watch

\n
watch(\n  () => settings,\n  settings => {\n    console.log(\'The new settings are\', settings);\n  },\n);\n\n
Run Code Online (Sandbox Code Playgroud)\n

遇到同样的问题。
\n当我只观察对象的属性时,它确实有效:

\n
watchEffect(() => {\n  console.log(\'Is the menu shown:\', settings.showMenu); // This works\n});\n\n
Run Code Online (Sandbox Code Playgroud)\n

通过解构,我可以看到一层深的变化,但不能看到更多层:

\n
watchEffect(() => {\n  // This works one level deep\n  console.log(\'Settings are changed:\', { ...settings });\n});\n\n
Run Code Online (Sandbox Code Playgroud)\n

可以使用 toRaw 记录设置,但不会触发 watchEffect:

\n
import { toRaw, watchEffect } from \'vue\';\n\nwatchEffect(() => {\n  // console.log shows the raw object, but watchEffect is not triggered\n  console.log(\'Settings are changed:\', toRaw(settings) );\n});\n\n
Run Code Online (Sandbox Code Playgroud)\n

是否有一种优雅的方法来监视反应式对象中任意深度的属性变化?

\n

Hen*_*Jan 14

经过更好地阅读文档后,我发现您可以提供如下watch()选项:{ deep: true }

import { toRaw, watch } from 'vue';

watch(
  () => settings,
  settings => {
    // use toRaw here to get a readable console.log result
    console.log('settings have changed', toRaw(settings));
  },
  { deep: true },
)
Run Code Online (Sandbox Code Playgroud)

watchEffect 不能以这种方式使用,因为 watchEffect 是通过对响应式属性的引用触发的,您必须循环整个对象并对所有值执行某些操作才能触发它。 watch()with{ deep: true }似乎是最好的选择。