It looks like a bug, why watch’s option deep do not work in reactive, but work in reactive getter?
1.Code
setup() {
    const state = reactive({
      id: 1,
      attrs: {
        date: new Date()
      }
    })
    watch(state, (val, prevVal) => {
      console.log('non-deep', val, prevVal)
    })
    watch(
      () => state,
      (val, prevVal) => {
        console.log('non-deep getter', val, prevVal)
      }
    )
    watch(
      state,
      (val, prevVal) => {
        console.log('deep', val, prevVal)
      },
      { deep: true }
    )
    watch(
      () => state,
      (val, prevVal) => {
        console.log('deep getter', val, prevVal)
      },
      { deep: true }
    )
    const changeDate = () => (state.attrs.date = new Date())
    return {
      state,
      changeDate
    }
  }
2.The console logs
non-deep Proxy {id: 1, attrs: {…}} Proxy {id: 1, attrs: {…}}
deep Proxy {id: 1, attrs: {…}} Proxy {id: 1, attrs: {…}}
deep getter Proxy {id: 1, attrs: {…}} Proxy {id: 1, attrs: {…}}
The Vue official document already points out that:
When you call watch() directly on a reactive object, it will implicitly create a deep watcher - the callback will be triggered on all nested mutations
watch function, the deep option will be ALWAYS true.watch function, the deep should respect your input options and works as expected.Extended for cases: Ref, ComputedRef
This is the code inside the watch function from the Vue source code:
if (isRef(source)) {
    getter = () => source.value
    forceTrigger = isShallow(source)
  } else if (isReactive(source)) {
    getter = () => source
    deep = true
  } else if (isArray(source)) {
    isMultiSource = true
    forceTrigger = source.some(isReactive)
    getter = () =>
      source.map(s => {
        ...
      })
  } else if (isFunction(source)) {
    if (cb) {
      // getter with cb
      getter = () =>
        callWithErrorHandling(source, instance, ErrorCodes.WATCH_GETTER)
    }
  ...
}
As we can see:
truesource.value and the deep option is the value you passed in. Note that, the value of ComputedRef will be replaced each calculation so the watch function will be trigger after any change of ComputedRef regardless deep optiondeep option is the value you passed inYou might ask what kind of my variables? Here is the answer:
const reactiveState = reactive({
  id: 1,
});
// reactiveState is reactive
const refState = ref({
  id: 1,
});
// refState is a Ref
// refState.value is reactive
const computedState = computed(() => {
  return {
    id: reactiveState.id,
  };
});
// computedState is a ComputedRef
// computedState.value is just a raw object without reactive. 
// so calling watch(() => computedState.value, callback) will NOT work
See this code example to verify what I said (you should open the dev tool to see the console logs)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With