Vue 3原始参考的React性作为一个 prop 通过

bihw5rsg  于 2023-02-05  发布在  Vue.js
关注(0)|答案(2)|浏览(174)

在玩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对象,我们就不需要这个额外的步骤。

xeufq47z

xeufq47z1#

但是当作为prop传递给子组件时,isRef()和isReactive()返回false。
正如你自己的评论所表明的那样,你在这里只讲述了故事的一半:

console.log("child check is reactive?",isReactive(props), isReactive(props.foo)); // returns true 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可以使用的地方。

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

// reactive AND synced with props.foo
const newFoo = toRef(props, 'foo')

正如我在上面的注解中指出的,如果您只使用ref创建一个新变量,它将是被动的,但它不会与其source属性同步,即当props.foo更新时,第一个newFoo不会被动更新,但第二个newFoo会。

bkhjykvo

bkhjykvo2#

简单的答案是,在儿童中,“props.foo”在设置/脚本中使用时是React性的(即根据我的经验,不在模板中),但如果 prop 被破坏(即const {foo} = props),“foo”就不是React性的。
但您应该使用toRef函数来完成此操作(const foo = toRef(props,'foo'))要特别确定使整个 prop 对象与toRefsReact(const reactiveProp = toRefs(props)),然后使用reactiveProp.foo引用它(即使你破坏它,它仍然是React性的)或者使用computed,例如const reactiveFoo = computed(()=>props.foo)。你可以到处玩(见我在这里的注解Vue Props Reactivity Playground)。
让我沮丧了一段时间,因为这不像React.js(我已经用了很长时间), prop 是被动的(即使被破坏)。

相关问题