Vue:如何在不失去反应性的情况下合并两个反应性对象

mar*_*lin 5 javascript vue.js vuejs3 vue-composition-api

考虑这个说明性示例:

const useFeatureX = () => {
  return Vue.reactive({
    x1: 2,
    x2: 3
  });
};

const useFeatureY = () => {
  return Vue.reactive({
    y1: 1,
    y2: 2
  });
};

const App = {
  setup() {
    return { ...useFeatureX(), ...useFeatureY() };
  }
};

Vue.createApp(App).mount("#root");
Run Code Online (Sandbox Code Playgroud)
input {
  max-width: 50px;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/vue@next"></script>
<div id="root">
  x1 + x2: <input type="number" v-model="x1"/> + <input type="number" v-model="x2"/> = {{ +x1 + +x2 }} <br/>
  y1 + y2: <input type="number" v-model="y1"/> + <input type="number" v-model="y2"/> = {{ +y1 + +y2 }}
</div>
Run Code Online (Sandbox Code Playgroud)

正如您在运行代码段时所看到的,在将两个对象从useFeatureX()和合并useFeatureY()为一个之后{ ...useFeatureX(), ...useFeatureY() },应用程序不再跟踪更新。

如何在不失去反应性的情况下合并两个反应性对象?

str*_*str 7

对象解构破坏了反应性

当我们想要使用大型反应式对象的一些属性时,使用 ES6 解构来获取我们想要的属性可能很诱人:

[...]

不幸的是,通过这种破坏,两种性质的反应性都会丢失。对于这种情况,我们需要将反应式对象转换为一组 refs。这些 refs 将保留与源对象的反应式连接:

相反,您可以使用 toRefs“[转换] 一个反应对象到一个普通对象,其中结果对象的每个属性都是一个指向原始对象相应属性的引用”。

const useFeatureX = () => {
  return Vue.reactive({
    x1: 2,
    x2: 3
  });
};

const useFeatureY = () => {
  return Vue.reactive({
    y1: 1,
    y2: 2
  });
};

const App = {
  setup() {
    return { ...Vue.toRefs(useFeatureX()), ...Vue.toRefs(useFeatureY()) };
  }
};

Vue.createApp(App).mount("#root");
Run Code Online (Sandbox Code Playgroud)
input {
  max-width: 50px;
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/vue@next"></script>
<div id="root">
  x1 + x2: <input type="number" v-model="x1"/> + <input type="number" v-model="x2"/> = {{ +x1 + +x2 }} <br/>
  y1 + y2: <input type="number" v-model="y1"/> + <input type="number" v-model="y2"/> = {{ +y1 + +y2 }}
</div>
Run Code Online (Sandbox Code Playgroud)