【问题标题】:Vue 3 How to use watch or watchEffect (and console.log) on a reactive object?Vue 3 如何在反应对象上使用 watch 或 watchEffect(和 console.log)?
【发布时间】:2021-05-09 19:07:38
【问题描述】:

我正在尝试(深入)观察 Vue 3 中反应性对象的任何变化:

import { reactive, watchEffect } from 'vue';

const settings = reactive({
  panes: {
    left: {
      defaultAction: "openInOtherPane",
    },
    right: {
      defaultAction: "openInThisPane",
    },
  },
  showMenu: false,
  isDrawerOpen: false,
});

watchEffect(() => {
  console.log('The new settings are', settings);
});

// Try to change a setting (this does not trigger watchEffect)
settings.panes.left.defaultAction = "none";

这段代码有两个问题:

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

我也试过watch

watch(
  () => settings,
  settings => {
    console.log('The new settings are', settings);
  },
);

同样的问题。
当我只看对象上的一个属性时,它确实有效:

watchEffect(() => {
  console.log('Is the menu shown:', settings.showMenu); // This works
});

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

watchEffect(() => {
  // This works one level deep
  console.log('Settings are changed:', { ...settings });
});

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

import { toRaw, watchEffect } from 'vue';

watchEffect(() => {
  // console.log shows the raw object, but watchEffect is not triggered
  console.log('Settings are changed:', toRaw(settings) );
});

是否有一种优雅的方法可以观察反应对象中任何级别的属性变化?

【问题讨论】:

    标签: javascript watch vuejs3 vue-composition-api vue-reactivity


    【解决方案1】:

    如果观察对象的第一级属性的变化就足够了,这对我来说效果非常好:

    watchEffect(() => {
      toRefs(objectToWatch)
      // perform some side effect
    })
    

    【讨论】:

      【解决方案2】:

      观察反应对象

      使用观察器来比较反应性数组或对象的值要求它具有仅由值组成的副本。

      const numbers = reactive([1, 2, 3, 4])
      
      watch(
        () => [...numbers],
        (numbers, prevNumbers) => {
          console.log(numbers, prevNumbers);
        })
      
      numbers.push(5) // logs: [1,2,3,4,5] [1,2,3,4]
      

      【讨论】:

      • 您的回答告诉我们如何查看ref() 值。我正在寻找一种观看reactive() 值的方法。
      【解决方案3】:

      在更好地阅读文档后,我发现您可以像这样给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 },
      )
      

      您不能以这种方式使用 watchEffect,因为 watchEffect 是由对反应性属性的引用触发的,并且您必须遍历整个对象并使用所有要触发的值来执行某些操作。 watch(){ deep: true } 似乎是最好的选择。

      【讨论】:

        猜你喜欢
        • 2020-06-16
        • 1970-01-01
        • 2019-07-22
        • 2021-05-30
        • 2021-06-04
        • 1970-01-01
        • 2018-12-07
        • 2021-11-15
        • 2019-11-01
        相关资源
        最近更新 更多