在玩Vue3React时,我遇到了一个我无法解释的行为。
我创建了一个原语的ref
。检查isRef
显然返回true
。但是当作为prop
传递给子组件时,isRef()
和isReactive()
返回false
。为什么?
另外,即使都返回false
,我在子组件中添加的这个prop的watcher在值改变时也会触发,如果watched值不是ref
也不是reactive
,怎么触发呢?
下面是一个用于父级和子级的代码片段:
Parent.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);
});
Child.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);
});
点击此处链接至Vue SFCPlayground
附加问题:当foo
被传递给子组件中使用的可组合对象时,除非我们通过toRef传递foo
,否则不会触发可组合对象中的观察器,但如果foo
是一个ref/reactive对象,我们就不需要这个额外的步骤。
2条答案
按热度按时间xeufq47z1#
但是当作为prop传递给子组件时,isRef()和isReactive()返回false。
正如你自己的评论所表明的那样,你在这里只讲述了故事的一半:
isReactive(props)
* 不 * 返回true,因为整个props
对象( Package 了foo
)是被动的。父对象对foo
所做的任何更新都会作为更新的props
对象传递给子对象。props.foo
确实不是ref/reactive,因为它不需要这样。只要props
是被动的,props.foo
将更新监视器能够在对
props.foo
进行更改时激活,因为您实际上使用了特殊语法,将“getter”传入监视器,该监视器专门用于监视React对象的 * 属性 *(在您的示例中:Vue文档中有一个例子也是这么说的。如果你需要给
props.foo
赋值给它自己的React变量,比如说传递给一个组合变量,这就是toRef可以使用的地方。正如我在上面的注解中指出的,如果您只使用
ref
创建一个新变量,它将是被动的,但它不会与其source属性同步,即当props.foo
更新时,第一个newFoo
不会被动更新,但第二个newFoo
会。bkhjykvo2#
简单的答案是,在儿童中,“props.foo”在设置/脚本中使用时是React性的(即根据我的经验,不在模板中),但如果 prop 被破坏(即
const {foo} = props
),“foo”就不是React性的。但您应该使用
toRef
函数来完成此操作(const foo = toRef(props,'foo')
)要特别确定或使整个 prop 对象与toRefs
React(const reactiveProp = toRefs(props)
),然后使用reactiveProp.foo
引用它(即使你破坏它,它仍然是React性的)或者使用computed
,例如const reactiveFoo = computed(()=>props.foo)
。你可以到处玩(见我在这里的注解Vue Props Reactivity Playground)。让我沮丧了一段时间,因为这不像React.js(我已经用了很长时间), prop 是被动的(即使被破坏)。