ค้นหาเว็บไซต์

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>

บทความที่เกี่ยวข้อง