Subscribe on changes!

Computed not able to track dependency when code has independent branches

avatar
Sep 28th 2020

Version

3.0.0

Reproduction link

https://jsfiddle.net/9ovab40z/

Steps to reproduce

  1. Click run in the jsfiddle
  2. Type in the input box, message doesn't change

What is expected?

The message should change as you type.

What is actually happening?

Message displayed remains the same


It seems the compiler is taking a shortcut to assume that code will only take the if branch since if we remove the if branch, everything works fine. But obviously the code can take else branch as well, so it should be reactive when name changes.

avatar
Sep 28th 2020

This is because JS can't track accesses to arbitrary variables, only properties on an object. If you make firstTime a ref it'll work just fine:

      let firstTime = Vue.ref(true);
      const message = Vue.computed(() => {
        if (firstTime.value) {
          firstTime.value = false;
          return "Welcome stranger";
        }
        return `Hello ${name.value}`;
      });
avatar
Sep 29th 2020

But we are not necessarily want to track access to firstTime, only name in this case. So ideally it should be only reactive with respect to changes of name variable regardless of the value of firstTime. A very hack way to make this work is this:

const message = Vue.computed(() => {
  name.value;
  if (firstTime) {
    return "Welcome stranger";
  }
  return `Hello ${name.value}`;
});

But it doesn't look right to me.

avatar
Sep 29th 2020

But we are not necessarily want to track access to firstTime, only name in this case. So ideally it should be only reactive with respect to changes of name variable regardless of the value of firstTime. A very hack way to make this work is this:

const message = Vue.computed(() => {
  name.value;
  if (firstTime) {
    return "Welcome stranger";
  }
  return `Hello ${name.value}`;
});

But it doesn't look right to me.

it doesn't work because of the name never been tracked in branches. when you add name.value at top of if (firstTime) {...},the name will be tracked and it work fine when the effect run. If you make firstTime to a ref, dependency will track again when the firstTime changed.

avatar
Sep 29th 2020

Okay, but shouldn't name be tracked regardless of the if statement? The following obviously also works. It stops working after we add an if statement:

const message = Vue.computed(() => {
  return `Hello ${name.value}`;
});
avatar
Sep 29th 2020

Okay, but shouldn't name be tracked regardless of the if statement? The following obviously also works. It stops working after we add an if statement:

const message = Vue.computed(() => {
  return `Hello ${name.value}`;
});

Vue3 collect field's dependency when it's getter() is called. "return Hello ${name.value}" never reach because of firstTime is true and it return "Welcome stranger" in your code.If firstTime is a ref.vue will collect dependency of firstTime when if (firstTime){...} is called. and then firstTime.value will be false. so ${name.value} is reachable and it's dependency will be collected in next run.

avatar
Sep 29th 2020

This is expected behavior. You can manually track any dependency by reading it at the top of the computed property like said at https://github.com/vuejs/vue-next/issues/2260#issuecomment-700352862