Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is toRaw(obj) maintaining reactivity?

I have a reactivity confusion regarding toRaw().

App.vue

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <TheForm @newThing="addNewThing" />
  <TheList :allTheThings="allTheThings" />
</template>

<script setup>
  import TheForm from "./components/TheForm.vue";
  import TheList from "./components/TheList.vue";

  import { ref } from "vue";

  const allTheThings = ref([]);
  const addNewThing = (thing) => allTheThings.value.push(thing);
</script>

TheForm.vue

<template>
  <h3>Add New Thing</h3>
  <form @submit.prevent="addNewThing">
    <input type="text" placeholder="description" v-model="thing.desc" />
    <input type="number" placeholder="number" v-model="thing.number" />
    <button type="submit">Add New Thing</button>
  </form>
</template>

<script setup>
  import { reactive, defineEmit, toRaw } from "vue";

  const emit = defineEmit(["newThing"]);

  const thing = reactive({
    desc: "",
    number: 0,
  });

  const addNewThing = () => emit("newThing", thing);
</script>

TheList.vue

<template>
  <h3>The List</h3>
  <ol>
    <li v-for="(thing, idx) in allTheThings" :key="idx">
      {{ thing.desc }} || {{ thing.number }}
    </li>
  </ol>
</template>

<script setup>
  import { defineProps } from "vue";

  defineProps({
    allTheThings: Array,
  });
</script>

As the code is passing around proxies to the data, it acts as suspected: after submitting the form, if you re-edit the data in the form fields it also edits the output of the list. Fine.

So I want to pass in a non-reactive copy of thing in addNewThing:

  const addNewThing = () => {
    const clone = { ...thing };
    emit("newThing", clone);
  };

And it works as expected.

What doesn’t work is if I use const clone = toRaw(thing); instead. If I log the output of each, { …thing} is EXACTLY the same as toRaw(thing) so why does toRaw() not seem to lose it’s reactivity?

Any light shone would be, well… enlightening.

like image 229
Adam Avatar asked Sep 03 '25 17:09

Adam


1 Answers

I think the issue is that there is a misunderstanding of what toRaw does.

Returns the raw, original object of a reactive or readonly proxy. This is an escape hatch that can be used to temporarily read without incurring proxy access/tracking overhead or write without triggering changes. It is not recommended to hold a persistent reference to the original object. Use with caution.

toRaw will return the raw Proxy, not a copy of the contents of the Proxy, so your solution to use const clone = { ...thing }; is IMHO appropriate, and hopefully this explanation is sufficient.

See similar question for more detail 👉 vue3 reactive unexpected behaviour

like image 76
Daniel Avatar answered Sep 05 '25 14:09

Daniel