Subscribe on changes!

Can watch Api not traverse the shallowReactive Object deep?

avatar
Nov 9th 2021

What problem does this feature solve?

Watch Api will traverse the shallowReactive Object deep. I want to set the third party object (such as { [key as string]: Graph } Graph is @antv/G6 Graph Object) to be ShallowReactive because i don't need it to be reactive deep. Even if these large objects are set to shallowReactive, they are still deep traverse in watch api. I think traverse the shallowReactive Object deep in watch api is not need because it improves performance.

Here is a demo that watch Api traverse the shallowReactive Object deep. https://codesandbox.io/s/vue3-watch-forked-6nj7j?file=/src/App.vue

I can use markRaw(object) to avoid traverse deep. But i think it can resolve in Vue when the obj is shallowReactive.

What does the proposed API look like?

add isShallowReactive to traverse. If isShallowReactive true, avoid to traverse deep.

export function traverse(value: unknown, seen?: Set<unknown>, isShallowReactive = true) {
  // ...
  else if (isPlainObject(value)) {
      for (const key in value) {
         !isShallow && traverse((value as any)[key], seen)
      }
    }
   return value
}

or in traverse function, if the value is shallowReactive, avoid to traverse deep.

  else if (isPlainObject(value)) {
    const isShallow = isShallowReacitve(value)
    for (const key in value) {
       !isShallow && traverse((value as any)[key], seen)
    }
  }
  return value
avatar
Nov 9th 2021

Deep watching is only possible on reactive data - watching relies on reactivity. So you are asking for the data in a shallowReactive to be reactive. Then just use reactive

Apologies, I totally misread.

avatar
Nov 9th 2021

Thinking about this a bit, I think something like that has been discussed previously. One of the issues with this approach is that it would then miss reactive data nested within the nonreactive data of shallowReactive:

const obj = shallowReactive({
  foo: {
    bar: ref(0)
  }
})

In the above example, after your proposed change, a watch would no longer pick up on obj.foo.bar.value being changed. That would technically be a breaking change which we can't introduce in the 3.* version range.

With markRaw, you can control the behaviour right now, so that might be a good enough workaround/compromise?

avatar
Nov 18th 2021

I'll close this as I don't see any arguments for a breaking change on the horizon.