Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a structuredClone of a Proxy object?

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!

like image 360
avenmia Avatar asked Sep 01 '25 16:09

avenmia


2 Answers

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;
}
like image 151
Jonas Schade Avatar answered Sep 04 '25 07:09

Jonas Schade


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'}] }
like image 21
Rémi Girard Avatar answered Sep 04 '25 06:09

Rémi Girard