为什么 toRaw(obj) 保持反应性?

Ada*_*dam 4 vue-reactivity vuejs3 vite

我对 toRaw() 的反应性感到困惑。

\n

应用程序.vue

\n
<template>\n  <img alt="Vue logo" src="./assets/logo.png" />\n  <TheForm @newThing="addNewThing" />\n  <TheList :allTheThings="allTheThings" />\n</template>\n\n<script setup>\n  import TheForm from "./components/TheForm.vue";\n  import TheList from "./components/TheList.vue";\n\n  import { ref } from "vue";\n\n  const allTheThings = ref([]);\n  const addNewThing = (thing) => allTheThings.value.push(thing);\n</script>\n
Run Code Online (Sandbox Code Playgroud)\n

TheForm.vue

\n
<template>\n  <h3>Add New Thing</h3>\n  <form @submit.prevent="addNewThing">\n    <input type="text" placeholder="description" v-model="thing.desc" />\n    <input type="number" placeholder="number" v-model="thing.number" />\n    <button type="submit">Add New Thing</button>\n  </form>\n</template>\n\n<script setup>\n  import { reactive, defineEmit, toRaw } from "vue";\n\n  const emit = defineEmit(["newThing"]);\n\n  const thing = reactive({\n    desc: "",\n    number: 0,\n  });\n\n  const addNewThing = () => emit("newThing", thing);\n</script>\n
Run Code Online (Sandbox Code Playgroud)\n

TheList.vue

\n
<template>\n  <h3>The List</h3>\n  <ol>\n    <li v-for="(thing, idx) in allTheThings" :key="idx">\n      {{ thing.desc }} || {{ thing.number }}\n    </li>\n  </ol>\n</template>\n\n<script setup>\n  import { defineProps } from "vue";\n\n  defineProps({\n    allTheThings: Array,\n  });\n</script>\n
Run Code Online (Sandbox Code Playgroud)\n

由于代码将代理传递给数据,因此它的行为与可疑的一样:提交表单后,如果您重新编辑表单字段中的数据,它也会编辑列表的输出。美好的。

\n

所以我想传递thingin的非反应式副本addNewThing

\n
  const addNewThing = () => {\n    const clone = { ...thing };\n    emit("newThing", clone);\n  };\n
Run Code Online (Sandbox Code Playgroud)\n

它按预期工作。

\n

\xe2\x80\x99t 不起作用的是如果我使用它const clone = toRaw(thing);。\n如果我记录每个的输出,则{ \xe2\x80\xa6thing}与它完全相同,toRaw(thing)那么为什么似乎toRaw()没有失去它\xe2\x80\x99s 的反应性?

\n

任何光芒都会照亮,\xe2\x80\xa6。

\n

Dan*_*iel 7

我认为问题在于对它的作用存在误解toRaw

reactive返回代理的原始对象readonly这是一个逃生舱口,可用于临时读取而不产生代理访问/跟踪开销或写入而不触发更改。不建议保留对原始对象的持久引用。谨慎使用。

toRaw将返回原始代理,而不是代理内容的副本,因此您使用的解决方案恕我const clone = { ...thing };直言是合适的,希望这个解释足够了。

有关更多详细信息,请参阅类似的问题 vue3 反应性意外行为

  • “toRaw 将返回原始代理”,但文档说“返回原始的原始对象”。如果 toRaw 只是禁用反应性但维护代理,则事实证明该文档具有误导性。代理不是原始对象。 (3认同)