vue.js - วิธีอ้างอิงวงกลมของคอมโพเนนต์ใน Vue 3 ด้วย Typescript อย่างถูกต้อง?
ฉันมีส่วนประกอบ Vue สองตัว เพื่อความเรียบง่ายของคำถามนี้ ฉันเรียกพวกมันว่า ส่วนประกอบ A และ ส่วนประกอบ B
ส่วนประกอบ A
<template>
<div>{{ recursive.text }} component A</div>
<component-b v-if="recursive.value" :recursive="recursive.value" />
</template>
<script lang="ts">
import { defineAsyncComponent, defineComponent } from 'vue';
export default defineComponent({
name: 'ComponentA',
components: {
ComponentB: defineAsyncComponent(() => import('./B.vue')),
},
});
</script>
<script lang="ts" setup>
interface RecursiveProp {
text: string;
value?: RecursiveProp;
}
const props = defineProps<{ recursive: RecursiveProp }>();
</script>
ส่วนประกอบ B
<template>
<div>{{ recursive.text }} component B</div>
<component-a v-if="recursive.value" :recursive="recursive.value" />
</template>
<script lang="ts">
import { defineAsyncComponent, defineComponent } from 'vue';
export default defineComponent({
name: 'ComponentB',
components: {
ComponentA: defineAsyncComponent(() => import('./A.vue')),
},
});
</script>
<script lang="ts" setup>
interface RecursiveProp {
text: string;
value?: RecursiveProp;
}
const props = defineProps<{ recursive: RecursiveProp }>();
</script>
ตัวอย่างเช่น เมื่อฉันนำเข้า Component A ไปยังคอมโพเนนต์อื่นและส่ง props ที่ถูกต้องให้ โค้ดทำงานได้โดยไม่มีข้อผิดพลาดใด ๆ ปรากฏในเบราว์เซอร์ Component A และ Component B จะทำการเรนเดอร์ซ้ำตามจำนวนที่ระบุโดย prop ที่ให้ แต่ด้วยเหตุผลบางอย่าง Visual Studio Code แสดงข้อผิดพลาดเมื่อคอมโพเนนต์อ้างอิงถึงกันแบบนี้ ฉันได้แนบรูปภาพของข้อผิดพลาดไว้ด้านล่าง ข้อผิดพลาดนี้เกิดขึ้นทั้งใน component A และ component B
ในเอกสารของ Vue ปัญหานี้ถูกอ้างถึงภายในส่วน การจัดการกรณีขอบเขตพิเศษ ปัญหาเพียงอย่างเดียวคือมันเป็นเอกสารของ Vue 2: https://v2.vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components
ใน Vue 3 คุณสามารถใช้ defineAsyncComponent สิ่งนี้ทำให้โค้ดของฉันทำงานได้ แต่ทำให้เกิดข้อผิดพลาดใน Visual Studio code: https://vuejs.org/guide/components/async.html#async-components=
ฉันรับทราบว่าฉันสามารถลงทะเบียนคอมโพเนนต์หนึ่งในระดับโลกได้ แต่สิ่งนั้นเป็นสิ่งที่ฉันต้องการหลีกเลี่ยง
มีวิธีใดบ้างในการอ้างอิงแบบวงกลมของคอมโพเนนต์ใน Vue 3 พร้อมกับ Typescript ได้อย่างถูกต้อง?
คำตอบ #1
ดูเหมือนว่าปัญหานี้ส่งผลกระทบเฉพาะกับ <script lang="ts"> และไม่เกี่ยวข้องกับ IDE หรือ <script setup lang="ts">
วิธีแก้ไขคือการลงทะเบียนคอมโพเนนต์แบบอซิงโครนัสที่เรียกซ้ำกันใน <script setup lang="ts"> แทน <script lang="ts">:
<!-- A.vue -->
<template>
<div>{{ recursive.text }} component A</div>
<component-b v-if="recursive.value" :recursive="recursive.value" />
</template>
<script lang="ts" setup>
import { defineAsyncComponent } from 'vue'
👇
const ComponentB = defineAsyncComponent(() => import('./B.vue'))
interface RecursiveProp {
text: string;
value?: RecursiveProp;
}
const props = defineProps<{ recursive: RecursiveProp }>();
</script>
<!-- B.vue -->
<template>
<div>{{ rec.text }} component B</div>
<component-a v-if="rec.value" :recursive="rec.value" />
</template>
<script lang="ts" setup>
import { defineAsyncComponent, computed } from 'vue'
👇
const ComponentA = defineAsyncComponent(() => import('./A.vue'))
interface RecursiveProp {
text: string;
value?: RecursiveProp;
}
const props = defineProps<{ recursive: RecursiveProp }>();
// compute stop-condition for the recursion
const rec = computed(() => ({
...props.recursive,
value: undefined
} as RecursiveProp))
</script>
เดโม
คำตอบ #2
ฉันคิดวิธีแก้ปัญหาแบบอื่น โดยใช้ defineOptions (ต้องใช้ Vue 3.3)
<!-- A.vue -->
<template>
<div>{{ recursive.text }} component A</div>
<component-b v-if="recursive.value" :recursive="recursive.value" />
</template>
<script lang="ts" setup>
import { defineAsyncComponent, defineOptions } from 'vue'
defineOptions({
components: { ComponentB: defineAsyncComponent(() => import('./B.vue')) }
})
interface RecursiveProp {
text: string;
value?: RecursiveProp;
}
const props = defineProps<{ recursive: RecursiveProp }>();
</script>
<!-- B.vue -->
<template>
<div>{{ rec.text }} component B</div>
<component-a v-if="rec.value" :recursive="rec.value" />
</template>
<script lang="ts" setup>
import { defineAsyncComponent, defineOptions, computed } from 'vue'
defineOptions({
components: { ComponentA: defineAsyncComponent(() => import('./A.vue')) }
})
interface RecursiveProp {
text: string;
value?: RecursiveProp;
}
const props = defineProps<{ recursive: RecursiveProp }>();
// compute stop-condition for the recursion
const rec = computed(() => ({
...props.recursive,
value: undefined
} as RecursiveProp))
</script>
