Subscribe on changes!

Export `trigger` from `@vue/reactive` in browser bundles.

avatar
Apr 18th 2022

What problem does this feature solve?

We have a few edge cases in our Vue 3 library (FormKit) where it would be useful to manually trigger the dependencies of a reactive property. This typically this happens during compute-heavy operations dealing with deeply nested objects and its important not to trigger any deps until a specific "time". The use cases are effectively the same as triggerRef but for properties of a reactive object (in a library where users can pass either reactive or ref).

Our hope is to do this by getting the reactive proxy target (via toRaw) running the expensive process, and then triggering the specific properties that were updated at a (slightly) later time. This can be done already using trigger from @vue/reactive — however since the browser bundle does not export trigger we cannot use this for users who want CDN support, even with an import map since the module scopes are different.

What does the proposed API look like?

Ultimately it would be great to be able to do:

import { trigger } from 'vue'

Where vue is any of the bundled versions.

avatar
Apr 19th 2022

Can't you build this with customRefs already though?

avatar
Apr 19th 2022

@posva I think it is only possible if we control the type of object passed to us. In our scenario, we expect users to be able to pass in a ref or a reactive without discrimination — and in this scenario I don't think customRef is enough (I would love to be proved wrong).

From reading the Vue reactivity source code my hunch is that deps of a reactive property are not copied to the ref.dep property during a toRef and triggerRefValue only operates on the effects in ref.dep.

Here's a minimal reproduction in the Vue SFC playground:

I suppose it would be possible, in theory to proxy the reactive object itself, not apply any changes to the object itself, but to some temporary facsimile, and then explicitly assign those values to the reactive object during a "trigger" event meaning the original reactive object would have direct assignments and its deps would be triggered but this would be a lot of unnecessary code and the underlying object that is being operated on would not be the same, so a WeakMap or a WeakSet could not track it properly.

A solution to all this would be some way to manually trigger the deps of a reactive object like triggerReactive.

avatar
Apr 19th 2022

Can't you set one of the reactive properties only like so

avatar
Apr 19th 2022

Thats interesting @posva — I suppose that works because the flush timing on those updates causes only 1 mutation to be made (wouldn't want multiple triggers).

Unfortunately — im not sure it works in our specific use case where v-model comes into play since the emits does not squash any events. A more fleshed out example where v-model is at play:

  • With v-model: http://brd.bz/7e1f4e7d
  • With spreading:: http://brd.bz/59a550ab — of course this works with spreading the objects, but we'd love to avoid this as any code using referencing these objects with Map/Set/WeakMap/WeakSet will be broken.
  • With re-assignment (like in your last example): http://brd.bz/60f3c932 — this seems pretty hacky, and unfortunately it still doesn't work

If we could emit the update:modelValue and explicitly trigger deps we'd be in a good place perhaps, but I think we still need some kind of access to trigger — again would love to be wrong