Subscribe on changes!

computed which uses value from later defined composable return, used in another composable breaks reactivity

avatar
May 3rd 2022

Version

3.2.33

Reproduction link

codesandbox.io

Steps to reproduce

This is a really strange edge-case but I spend a significant amount of time and could not find as solution, therefore it might actually be a bug.

  • Open minimal reproduction
  • Open useFirstComposable.js and make sure the the line for Case 2 is commented in
  • Run the application
  • The console shows logs for interval and compute computedPropExample
  • Comment out Case 2 and comment in Case 1
  • Run the application
  • The console only shows logs for interval, the computed property does not get computed anymore

The only difference (I think) between Case 1 and Case 2 ist that I'm accessing the passed ComputedRef.

What is expected?

The computed property gets recomputed when Case 2 is active

What is actually happening?

The computed property is not recomputed when Case 2 is active

avatar
May 3rd 2022

The computed property doesn't access any reactive variables in Case 1, because at the moment that you read from the computed, secondComposable hasn't been set yet and you have this in your computed as the first line:

 if (!secondComposable) return false;

So this computable will now never update again, because it doesn't have to. secondComposable is not a reactive value, so changing it later will not trigger a re-evalutation, annd no other variables were accessed in the first read of the computed.

avatar
May 3rd 2022

Thanks @LinusBorg for the explanation, it makes perfect sense! For anyone who might find this issue with a similar problem, this can be circumvented by using a shallowRef:

setup() {
    const secondComposable = shallowRef();

    const computedPropExample = computed(() => {
      if (!secondComposable.value) return false;

      console.log(
        "compute computedPropExample",
        secondComposable.value.isActive.value
      );
      return secondComposable.value.isActive.value;
    });

    useFirstComposable(computedPropExample);

    secondComposable.value = useSecondComposable();

    return {
      computedPropExample,
    };
  },

https://codesandbox.io/s/vue-composable-solution-vlbglj?file=/src/components/MyComponent.vue