Computed not able to track dependency when code has independent branches
Version
3.0.0
Reproduction link
https://jsfiddle.net/9ovab40z/
Steps to reproduce
- Click run in the jsfiddle
- 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.
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}`;
});
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.
But we are not necessarily want to track access to
firstTime
, onlyname
in this case. So ideally it should be only reactive with respect to changes ofname
variable regardless of the value offirstTime
. 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.
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}`;
});
Okay, but shouldn't
name
be tracked regardless of theif
statement? The following obviously also works. It stops working after we add anif
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.
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