Vue3 变换 props 结构保持反应性

发布于 2025-01-17 21:21:04 字数 2491 浏览 1 评论 0原文

我有一个从API获取数据并将其传递给显示它的组件(再次传递到多个子组件)的组件。因此,我试图将这些信息分为多个REF对象,以传递到每个子组件。

问题是,我会失去反应性...新的ref对象不会在父组件更改其数据时更新。

我创建了一个示例来显示问题。

parentComponent

<template>
  <p>All data: {{ data }}</p>
  <child-component :data="data"></child-component>
</template>
<script setup>
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue";

let data = ref({
  a: {},
  b: {},
  c: {}, // More properties...
});

setTimeout(() => { // FAKE API
  data.value.a = {
    name: "prop A",
    description: "aaa"
  };
  data.value.b = {
    name: "prop B",
    description: "bbb"
  };
  data.value.c = {
    name: "prop C",
    description: "ccc"
  };
  // More properties updated...
}, 2000);
</script>

ChildComponent

<template>
  <p>child component props: {{data}}</p>
  <p>child component manipulated: {{manipulated}}</p>
</template>

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

const props = defineProps(['data'])

let manipulated = ref({ // Only need a and b properties.
  a: props.data.a,
  b: props.data.b
})

</script>

输出端子组件

All data: { "a": {}, "b": {}, "c": {} }

child component props: { "a": {}, "b": {}, "c": {} }

child component manipulated: { "a": {}, "b": {} }

在更新后的parent组件数据后输出时输出:

All data: { "a": { "name": "prop A", "description": "aaa" }, "b": { "name": "prop B", "description": "bbb" }, "c": { "name": "prop C", "description": "ccc" } }

child component props: { "a": { "name": "prop A", "description": "aaa" }, "b": { "name": "prop B", "description": "bbb" }, "c": { "name": "prop C", "description": "ccc" } }

child component manipulated: { "a": {}, "b": {} }

更新后的父组件数据后所需的结果:

All data: { "a": { "name": "prop A", "description": "aaa" }, "b": { "name": "prop B", "description": "bbb" }, "c": { "name": "prop C", "description": "ccc" } }

child component props: { "a": { "name": "prop A", "description": "aaa" }, "b": { "name": "prop B", "description": "bbb" }, "c": { "name": "prop C", "description": "ccc" } }

child component manipulated: { "a": { "name": "prop A", "description": "aaa" }, "b": { "name": "prop B", "description": "bbb" } }

如何实现?借助原语的作用...但是有了物体,缺少某些东西来维持反应性...

I have a component that gets data from the API and passes it to another component that displays it (passing down again to multiple child components). So I tried to split that information into multiple ref objects for passing down to each child component.

The problem is, doing that I loose reactivity... the new ref object does not update when parent component changes their data.

I created an example to show the problem.

ParentComponent

<template>
  <p>All data: {{ data }}</p>
  <child-component :data="data"></child-component>
</template>
<script setup>
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue";

let data = ref({
  a: {},
  b: {},
  c: {}, // More properties...
});

setTimeout(() => { // FAKE API
  data.value.a = {
    name: "prop A",
    description: "aaa"
  };
  data.value.b = {
    name: "prop B",
    description: "bbb"
  };
  data.value.c = {
    name: "prop C",
    description: "ccc"
  };
  // More properties updated...
}, 2000);
</script>

ChildComponent

<template>
  <p>child component props: {{data}}</p>
  <p>child component manipulated: {{manipulated}}</p>
</template>

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

const props = defineProps(['data'])

let manipulated = ref({ // Only need a and b properties.
  a: props.data.a,
  b: props.data.b
})

</script>

Output when mount components

All data: { "a": {}, "b": {}, "c": {} }

child component props: { "a": {}, "b": {}, "c": {} }

child component manipulated: { "a": {}, "b": {} }

Output after updated parent component data:

All data: { "a": { "name": "prop A", "description": "aaa" }, "b": { "name": "prop B", "description": "bbb" }, "c": { "name": "prop C", "description": "ccc" } }

child component props: { "a": { "name": "prop A", "description": "aaa" }, "b": { "name": "prop B", "description": "bbb" }, "c": { "name": "prop C", "description": "ccc" } }

child component manipulated: { "a": {}, "b": {} }

Desired result after updated parent component data:

All data: { "a": { "name": "prop A", "description": "aaa" }, "b": { "name": "prop B", "description": "bbb" }, "c": { "name": "prop C", "description": "ccc" } }

child component props: { "a": { "name": "prop A", "description": "aaa" }, "b": { "name": "prop B", "description": "bbb" }, "c": { "name": "prop C", "description": "ccc" } }

child component manipulated: { "a": { "name": "prop A", "description": "aaa" }, "b": { "name": "prop B", "description": "bbb" } }

How can achieve that? With primitives works... but with objects there is missing something to maintain the reactivity...

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

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

发布评论

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

评论(1

对岸观火 2025-01-24 21:21:04

选项 1:使用深度观察程序

您可以使用 深度观察程序(即, watchprops.data 上的 deep 标志),用 props.data 的新值更新 manipulated

// ChildComponent.vue
import { watch } from 'vue'
⋮
watch(
  () => props.data,
  newValue => {
    const { a, b } = newValue
    manipulated.value = { a, b }
  },
  { deep: true }
)

演示 1

选项2:使用compulated

如果manipulated只是一个只读道具,你可以从refwatch切换改为计算

import { computed } from 'vue'

const props = defineProps(['data'])

let manipulated = computed(() => ({
  a: props.data.a,
  b: props.data.b,
}))

演示 2

Option 1: Use deep watcher

You could use a deep watcher (i.e., watch with the deep flag) on props.data that updates manipulated with the new values of props.data:

// ChildComponent.vue
import { watch } from 'vue'
⋮
watch(
  () => props.data,
  newValue => {
    const { a, b } = newValue
    manipulated.value = { a, b }
  },
  { deep: true }
)

demo 1

Option 2: Use computed

If manipulated were just a read-only prop, you could switch from the ref and watch to a computed instead:

import { computed } from 'vue'

const props = defineProps(['data'])

let manipulated = computed(() => ({
  a: props.data.a,
  b: props.data.b,
}))

demo 2

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