无法在ref变量的值上使用构造克隆()

发布于 2025-02-07 18:47:52 字数 840 浏览 1 评论 0 原文

我想利用 structuredclone() vue应用。我想使用它来创建一个深度克隆(而不是使用诸如Stringify和Parse或外部库之类的解决方法)。在我的设置功能中,以下代码很好

const a = {
  foo: {
    bar: "+"
  }
};
const b = structuredClone(a);

console.log(b);

但是我不可能在ref变量的值上使用它。此示例代码

import { ref } from "vue";
const a = ref({ foo: { bar: "+" } });
const b = structuredClone(a.value);

引发错误

未能达到的domexception:无法在“窗口”上执行“构造克隆”:#无法克隆。

Ref数组中的项目也是如此

import { ref } from "vue";
const a = ref([{ foo: { bar: "+" } }]);
for (const b of a.value) {
  const c = structuredClone(b);
}

I want to make use of the structuredClone() function inside my Vue app. I want to use this to create a deep clone ( instead of using workarounds like stringify and parse or external libraries ). Inside my setup function the following code is fine

const a = {
  foo: {
    bar: "+"
  }
};
const b = structuredClone(a);

console.log(b);

But it is not possible for me to use it on values of ref variables. This example code

import { ref } from "vue";
const a = ref({ foo: { bar: "+" } });
const b = structuredClone(a.value);

throws the error

Uncaught DOMException: Failed to execute 'structuredClone' on 'Window': # could not be cloned.

The same goes for items from ref arrays

import { ref } from "vue";
const a = ref([{ foo: { bar: "+" } }]);
for (const b of a.value) {
  const c = structuredClone(b);
}

How can this be fixed?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

肩上的翅膀 2025-02-14 18:47:53

该错误意味着 structuredclone 是在 proxy 实例上执行的,无法克隆。为了允许,应该在原始对象上使用代理包装:

const b = structuredClone(toRaw(a.value));

请注意, toraw a.value 上使用,因为这两个 a a 和 a.Value 是反应性对象, Toraw 工作浅,需要应用于最内向的对象。

由于 ref 反应性允许构成反应性对象,因此 toraw 由于其工作方式而可能不起作用:

ref({ foo: { bar: barRef } })

这将需要递归地使用 Toraw 在使用 structuredClone 之前,在反应性对象上。在这一点上,这并不比手动克隆对象更容易,除非正在使用 set 等的更奇特的对象。

The error means that structuredClone was executed on Proxy instance, which cannot be cloned. In order to allow this, it should be used on raw object that a proxy wraps:

const b = structuredClone(toRaw(a.value));

Notice that toRaw is used on a.value because both a and a.value are reactive objects, and toRaw works shallowly and needs to be applied to the innermost object.

Since ref and reactive allow to compose reactive objects, toRaw still may not work for them due to how it works:

ref({ foo: { bar: barRef } })

This would require to recursively use toRaw on reactive objects before using structuredClone. At this point this doesn't make it easier than cloning the objects manually, unless more exotic objects like Set, Map, etc are in use.

梦醒时光 2025-02-14 18:47:53
import {
  toRaw,
  isRef,
  isReactive,
  isProxy,
} from 'vue';

export function deepToRaw<T extends Record<string, any>>(sourceObj: T): T {
  const objectIterator = (input: any): any => {
    if (Array.isArray(input)) {
      return input.map((item) => objectIterator(item));
    } if (isRef(input) || isReactive(input) || isProxy(input)) {
      return objectIterator(toRaw(input));
    } if (input && typeof input === 'object') {
      return Object.keys(input).reduce((acc, key) => {
        acc[key as keyof typeof acc] = objectIterator(input[key]);
        return acc;
      }, {} as T);
    }
    return input;
  };

  return objectIterator(sourceObj);
}

hulkmaster

您也可以用这样的UNRE包裹源bj。
Objectiterator(UNREF(sourceObj)))

import {
  toRaw,
  isRef,
  isReactive,
  isProxy,
} from 'vue';

export function deepToRaw<T extends Record<string, any>>(sourceObj: T): T {
  const objectIterator = (input: any): any => {
    if (Array.isArray(input)) {
      return input.map((item) => objectIterator(item));
    } if (isRef(input) || isReactive(input) || isProxy(input)) {
      return objectIterator(toRaw(input));
    } if (input && typeof input === 'object') {
      return Object.keys(input).reduce((acc, key) => {
        acc[key as keyof typeof acc] = objectIterator(input[key]);
        return acc;
      }, {} as T);
    }
    return input;
  };

  return objectIterator(sourceObj);
}

By hulkmaster https://github.com/vuejs/core/issues/5303#issuecomment-1543596383

You can also wrap the sourceObj with unref like this.
objectIterator(unref(sourceObj))

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文