作为 prop 传递的原始 ref 的 Vue 3 反应性

wal*_*lox 2 vue.js vuejs3 vue-composition-api

在玩 Vue 3 反应性时,我遇到了一种我无法解释的行为。

我创建了一个ref原语。检查isRef一下,显然返回了true。但是当作为 a 传递给子组件时propisRef()也会isReactive()返回false。为什么 ?

另外,即使它们都返回false,如果值发生变化,我在子组件中添加的这个道具的观察者也会被触发。如果监视的值不是refor ,它如何触发reactive

这是父级和子级的代码片段:

家长.vue

let foo = ref(0);
function changeFoo() {
  foo.value++;
}
  
console.log("parent check is reactive?", isReactive(foo)); // retruns false
console.log("parent check is ref?", isRef(foo)); // retruns true

watch(foo, (value, oldValue) => {
  console.log("foo changing from", oldValue, "to ", value);
});
Run Code Online (Sandbox Code Playgroud)

儿童.vue

const props = defineProps<{
  foo: number;
}>();

console.log("child check is reactive?",isReactive(props), isReactive(props.foo)); // returns true false
console.log("child check is ref ?",isRef(props), isRef(props.foo)); // returns false false // Question 1: Why props.foo is not a Ref ?
  
watch(props, (value, oldValue) => {
  console.log("props changing from", oldValue, " to ", value);
});
 
watch(()=>props.foo, (value, oldValue) => {
  // Question 2: Why this Watcher detects changes of "foo" without it being a ref nor reactive ?
  console.log("props.foo changing from ", oldValue, " to ", value);
});
Run Code Online (Sandbox Code Playgroud)

此处还有 Vue SFC Playground 的链接

额外问题:当foo传递给子组件中使用的可组合项时,除非我们通过 toRef 传递,否则不会触发可组合项内的观察程序,但如果是 ref/reactive 对象,foo则不需要此额外步骤。foo为什么基元需要这个加法步骤?

yod*_*duh 5

但是当作为 prop 传递给子组件时, isRef() 和 isReactive() 返回 false。

您在这里只讲述了故事的一半,正如您自己的评论实际上表明的那样:

console.log("child check is reactive?",isReactive(props), isReactive(props.foo)); // returns true false
Run Code Online (Sandbox Code Playgroud)

isReactive(props) 确实返回 true,因为整个props对象(包装foo)是反应性的。父级对 进行的任何更新foo都会作为更新的对象传递给子级props。这确实props.foo不是 ref/reactive,因为它不需要这样。只要props有反应props.foo就会更新

观察者能够在更改时激活,props.foo因为您实际上使用了特殊的语法,其中您向观察者传递了一个“getter”,专门用于观察反应对象的属性(在您的情况下: props )。Vue 文档中有一个示例说了同样的事情。

如果您需要分配props.foo给它自己的反应变量,比如传递给可组合项,那么就可以使用 toRef 。

// reactive but not synced with props.foo
const newFoo = ref(props.foo)

// reactive AND synced with props.foo
const newFoo = toRef(props, 'foo')
Run Code Online (Sandbox Code Playgroud)

正如我在上面的评论中指出的,如果您使用 just 创建一个新变量ref,它将是反应性的,但它不会与其源属性同步,即第一个newFoo在更新时不会反应性更新props.foo,但第二个newFoo会。Vue 文档中对此也有很好的解释