I'm using Vue3 where a lot of the objects are Proxy objects for reactivity. I want to create a deep copy of one of the proxy objects and recently discovered structuredClone.
https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
When I run the following code, I get an error performing a structuredClone on proxyObj:
const obj = {
name: "Steve",
age: 50
}
const handler = {}
const proxyObj = new Proxy(obj, {})
console.log(proxyObj)
const objCopy = structuredClone(obj)
console.log(objCopy)
const proxyObjCopy = structuredClone(proxyObj)
console.log(objCopy)
Uncaught DOMException: Failed to execute 'structuredClone' on 'Window': # could not be cloned.
Is there a way I can clone the proxy object? Is there a way I can dereference it first, copy it, and not lose the reactivity? Any help is appreciated!
If you're just talking about Vue3 and no nested proxies you could just use toRaw
directly:
import { reactive, toRaw } from 'vue';
const obj = reactive({ foo: 'bar' });
const objCopy = structuredClone(toRaw(obj)):
Having come across a few cases where I had objects with nested proxies or arrays of proxies etc, I had to go the extra mile and create my own toRawDeep
.
Since it uses toRaw
it should work with proxies created by reactive()
, readonly()
, shallowReactive()
or shallowReadonly()
.
import { toRaw } from 'vue';
export function toRawDeep<T>(observed: T): T {
const val = toRaw(observed);
if (Array.isArray(val)) {
return val.map(toRawDeep) as T;
}
if (val === null) return null as T;
if (typeof val === 'object') {
const entries = Object.entries(val).map(([key, val]) => [key, toRawDeep(val)]);
return Object.fromEntries(entries);
}
return val;
}
A simple way is to to convert Proxy object to standard object. Check this answer : https://stackoverflow.com/a/77144575/5372505
In the case you presented :
const obj = {
name: "John",
age: 50,
children: [{
name: 'Sam'
}]
};
const proxyObj = new Proxy(obj, {});
const objOneLevelCopy = {...proxyObj};
// const objCopy = structuredClone(proxyObj) // throw Error
const objStructuredCopy = structuredClone({...proxyObj});
obj.name = 'Amanda' // change a value
obj.children[0].name = 'Mike'; // change a sub value
console.log({obj}) // { name: "Amanda", age: 50, children: [{name: 'Mike'}] }
console.log({proxyObj}) // { name: "Amanda", age: 50, children: [{name: 'Mike'}] }
console.log({objOneLevelCopy}) // { name: "John", age: 50, children: [{name: 'Mike'}] }
console.log({objStructuredCopy}); // { name: "John", age: 50, children: [{name: 'Sam'}] }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With