Vue 3 Teleport dan Suspense: Pola Lanjutan dan Pertanyaan Interview 2026
Pelajari pola lanjutan Vue 3 Teleport dan Suspense untuk interview developer senior. Panduan lengkap dengan contoh kode dan best practices 2026.

Vue 3 Teleport dan Suspense menyelesaikan dua tantangan rendering yang berbeda: menempatkan komponen di luar hierarki DOM dan mengoordinasikan dependensi async. Keduanya adalah komponen bawaan yang tidak memerlukan import, dan keduanya sering muncul dalam interview developer Vue senior.
Vue 3.5 menambahkan prop defer ke Teleport, yang memungkinkan target dirender setelah komponen tree. Ini menyelesaikan masalah timing SSR yang umum di mana target portal tidak ada saat mount.
Dasar-Dasar Teleport dan Prop defer
Teleport memindahkan konten yang dirender ke lokasi DOM yang berbeda sambil mempertahankan component tree Vue. Komponen tetap menjadi child logis dari parent-nya: props, events, dan provide/inject semuanya bekerja normal. Vue DevTools menampilkan komponen yang di-teleport bersarang di bawah parent-nya, bukan di bawah elemen target.
<!-- ModalTrigger.vue -->
<script setup>
import { ref } from 'vue'
const isOpen = ref(false)
</script>
<template>
<button @click="isOpen = true">Open Modal</button>
<Teleport to="#modal-root">
<div v-if="isOpen" class="modal-overlay" @click.self="isOpen = false">
<div class="modal-content">
<slot />
<button @click="isOpen = false">Close</button>
</div>
</div>
</Teleport>
</template>Prop to menerima string CSS selector atau referensi elemen DOM. Ketika target tidak ada saat mount, Teleport memberikan warning dan tidak merender apa pun. Ini menciptakan masalah dengan SSR dan layout dinamis.
Prop defer (Vue 3.5+)
Prop defer memberitahu Teleport untuk menunggu hingga bagian lain dari aplikasi telah ter-mount sebelum menyelesaikan target. Ini memungkinkan teleporting ke elemen yang dirender kemudian dalam komponen yang sama atau komponen sibling.
<!-- App.vue -->
<template>
<Teleport defer to="#dynamic-target">
<NotificationBanner />
</Teleport>
<!-- Target dirender setelah Teleport -->
<div id="dynamic-target"></div>
</template>Tanpa defer, kode ini gagal karena #dynamic-target tidak ada saat Teleport mount. Dengan defer, Vue menyelesaikan target setelah semua komponen dalam tick yang sama telah ter-mount. Target masih harus dirender dalam siklus mount atau update yang sama.
Multiple Teleport dan Conditional Rendering
Multiple komponen Teleport dapat menargetkan elemen yang sama. Konten ditambahkan sesuai urutan deklarasi:
<template>
<Teleport to="#notifications">
<Toast message="First" />
</Teleport>
<Teleport to="#notifications">
<Toast message="Second" />
</Teleport>
</template>
<!-- Hasil di #notifications:
<div>First</div>
<div>Second</div>
-->Prop disabled mengontrol apakah teleportasi terjadi. Ketika disabled, konten dirender inline. Pola ini menangani layout responsif di mana modal harus overlay di desktop tetapi render inline di mobile:
<script setup>
import { useMediaQuery } from '@vueuse/core'
const isMobile = useMediaQuery('(max-width: 768px)')
</script>
<template>
<Teleport to="body" :disabled="isMobile">
<MobileDrawer />
</Teleport>
</template>Suspense untuk Orkestrasi Komponen Async
Suspense mengoordinasikan dependensi async di seluruh component tree. Ketika komponen descendant memiliki dependensi async yang belum resolved, Suspense menampilkan konten slot fallback. Setelah semua dependensi resolved, Suspense beralih ke slot default.
Suspense tetap eksperimental di Vue 3.5. API mungkin berubah sebelum mencapai status stabil. Penggunaan production memerlukan penerimaan risiko ini.
<!-- Dashboard.vue -->
<template>
<Suspense>
<template #default>
<DashboardContent />
</template>
<template #fallback>
<LoadingSpinner />
</template>
</Suspense>
</template>Suspense melacak dua tipe dependensi async: komponen dengan async setup() dan komponen async yang dibuat dengan defineAsyncComponent.
Async Setup dengan Top-Level Await
Vue 3 script setup mendukung top-level await. Komponen apa pun yang menggunakan top-level await menjadi dependensi async yang dapat dilacak Suspense:
<!-- UserProfile.vue -->
<script setup>
const response = await fetch('/api/user/profile')
const user = await response.json()
</script>
<template>
<div class="profile">
<h1>{{ user.name }}</h1>
<p>{{ user.email }}</p>
</div>
</template>Komponen ini tidak dapat dirender sampai fetch selesai. Suspense boundary parent menampilkan fallback sampai resolusi. Tanpa Suspense boundary, komponen tidak dirender.
Nested Suspense dengan Prop suspensible
Aplikasi kompleks sering memiliki multiple async boundary. Vue 3.3 memperkenalkan prop suspensible untuk mengontrol bagaimana komponen Suspense bersarang berinteraksi dengan parent-nya.
<!-- PageLayout.vue -->
<template>
<Suspense>
<template #default>
<header>
<AsyncNavigation />
</header>
<main>
<!-- Inner Suspense dengan fallback sendiri -->
<Suspense suspensible>
<template #default>
<AsyncContent />
</template>
<template #fallback>
<ContentSkeleton />
</template>
</Suspense>
</main>
</template>
<template #fallback>
<PageSkeleton />
</template>
</Suspense>
</template>Ketika suspensible diset, Suspense inner mendaftar dengan Suspense boundary parent. Parent menunggu AsyncNavigation dan AsyncContent untuk resolve sebelum menyembunyikan fallback-nya. Suspense inner masih berfungsi sebagai boundary lokal: jika AsyncContent memakan waktu lebih lama, ContentSkeleton ditampilkan sementara AsyncNavigation tetap terlihat.
Tanpa suspensible, Suspense inner beroperasi secara independen. Parent menampilkan fallback-nya hanya saat AsyncNavigation loading, mengabaikan AsyncContent sepenuhnya.
Siap menguasai wawancara Vue.js / Nuxt.js Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
Menggabungkan Teleport, Suspense, dan Transitions
Aplikasi nyata menggabungkan pola-pola ini. Modal yang memuat konten secara async mendapat manfaat dari ketiganya:
<!-- AsyncModal.vue -->
<script setup>
import { ref, defineAsyncComponent } from 'vue'
const isOpen = ref(false)
const AsyncModalContent = defineAsyncComponent({
loader: () => import('./ModalContent.vue'),
loadingComponent: () => import('./ModalSkeleton.vue'),
delay: 200,
timeout: 10000
})
</script>
<template>
<button @click="isOpen = true">Open</button>
<Teleport to="body">
<Transition name="modal">
<div v-if="isOpen" class="modal-wrapper">
<Suspense>
<template #default>
<AsyncModalContent @close="isOpen = false" />
</template>
<template #fallback>
<ModalSkeleton />
</template>
</Suspense>
</div>
</Transition>
</Teleport>
</template>
<style>
.modal-enter-active,
.modal-leave-active {
transition: opacity 0.3s ease;
}
.modal-enter-from,
.modal-leave-to {
opacity: 0;
}
</style>Urutan nesting penting: Teleport membungkus Transition, yang membungkus elemen conditional, yang berisi Suspense. Ini memastikan transition menganimasi seluruh modal termasuk loading state.
Error Handling dengan Suspense
Suspense tidak menangani error. Dependensi async yang gagal me-reject promise-nya dan mempropagasi error ke atas component tree. Lifecycle hook onErrorCaptured menangkap error ini di boundary:
<!-- ErrorBoundary.vue -->
<script setup>
import { ref, onErrorCaptured } from 'vue'
const error = ref(null)
onErrorCaptured((err) => {
error.value = err
return false // Mencegah propagasi
})
</script>
<template>
<div v-if="error" class="error-state">
<p>Failed to load: {{ error.message }}</p>
<button @click="error = null">Retry</button>
</div>
<Suspense v-else>
<template #default>
<slot />
</template>
<template #fallback>
<slot name="loading" />
</template>
</Suspense>
</template>Pola ini membungkus component tree async apa pun dengan loading dan error state. Tombol retry membersihkan error, menyebabkan Vue me-render ulang dan mencoba ulang operasi async.
Pertanyaan Interview tentang Teleport dan Suspense
Posisi Vue senior semakin sering menguji pola-pola ini. Berikut pertanyaan umum dan apa yang membedakan jawaban kuat:
Q: Kapan Teleport sebaiknya digunakan dibanding CSS positioning?
Jawaban lemah: "Ketika z-index tidak bekerja."
Jawaban kuat: Teleport menyelesaikan masalah hierarki DOM yang tidak bisa diselesaikan CSS. Modal di dalam container dengan overflow: hidden atau transform membuat stacking context baru, merusak position: fixed. Teleport memindahkan modal ke body, keluar dari constraint ini sambil mempertahankan component tree logis Vue.
Q: Bagaimana Suspense berbeda dari loading state di setiap komponen?
Jawaban lemah: "Suspense lebih bersih."
Jawaban kuat: Suspense mengoordinasikan multiple dependensi async. Sepuluh komponen dengan loading state individual menampilkan sepuluh spinner pada waktu berbeda. Suspense menampilkan satu spinner sampai kesepuluhnya resolve, kemudian menampilkan semuanya bersama. Ini menciptakan performa yang lebih mulus dan kode komponen yang lebih sederhana karena komponen async tidak perlu mengelola loading state sendiri.
Q: Apa yang terjadi ketika target Teleport tidak ada?
Konten tidak dirender dan Vue mencatat warning. Prop defer Vue 3.5 mengatasi ini dengan menunggu komponen lain ter-mount terlebih dahulu. Tanpa defer, pastikan target ada di index.html atau di komponen parent yang ter-mount sebelum children.
Q: Bisakah Suspense bekerja dengan Options API?
Ya. Komponen apa pun dengan async setup() memicu Suspense, terlepas dari apakah menggunakan Composition API atau Options API di tempat lain. Fungsi setup adalah async boundary, bukan style komponen.
Teleport dan Suspense di Nuxt 3
Nuxt 3 memperluas pola-pola ini dengan pertimbangan SSR. Dokumentasi Nuxt tentang SSR mencakup timing hydration.
Untuk Teleport, Nuxt memerlukan target ada sebelum hydration. Tambahkan target portal ke app.vue atau gunakan prop defer:
<!-- app.vue -->
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
<!-- Target portal untuk SSR -->
<div id="modal-root"></div>
<div id="toast-root"></div>
</template>Untuk Suspense, useFetch dan useAsyncData Nuxt terintegrasi secara otomatis. Komponen halaman yang menggunakan composable ini bekerja dengan Suspense bawaan Nuxt tanpa konfigurasi manual. Lihat modul Vue composables SharpSkill untuk persiapan interview terkait.
Pola Production untuk Vue 3.5
- Target Teleport di index.html: Buat target portal stabil yang ada sebelum kode Vue berjalan. Ini menghindari masalah timing sepenuhnya.
- Suspense boundary granular: Satu Suspense per unit loading independen. Dashboard dengan widget terpisah mendapat manfaat dari Suspense boundary terpisah sehingga widget cepat muncul segera.
- Error boundary di atas Suspense: Selalu bungkus Suspense dengan error handling. Network failure dan API error tidak boleh crash seluruh tree.
- Timing transition: Ketika menggabungkan Suspense dengan Transition, set
mode="out-in"untuk mencegah overlap selama perubahan state.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Bisakah kamu menemukan bug di Vue.js / Nuxt.js?
Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Ditulis oleh
Anthony Fillion-MailletPendiri SharpSkill
Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.
Diperbarui 28 Agustus 2026
Bagikan
Artikel terkait

Vue 3 Script Setup dan defineModel di 2026: Sintaks Modern dan Pertanyaan Interview
Panduan lengkap tentang sintaks script setup Vue 3, defineModel untuk two-way binding, reactive props destructure di Vue 3.5, dan pertanyaan interview yang sering diajukan.

Nuxt 4 SEO dan Meta Tags 2026: Panduan Lengkap useHead, useSeoMeta untuk Wawancara
Pelajari cara menggunakan useHead dan useSeoMeta di Nuxt 4 untuk optimasi SEO. Panduan lengkap dengan contoh kode dan pertanyaan wawancara teknis Vue/Nuxt.

Vue 3 Reactivity Transform di 2026: $ref, $computed dan Pertanyaan Interview
Panduan mendalam tentang Reactivity Transform Vue 3 meliputi $ref, $computed, dan pertanyaan interview yang sering diajukan untuk developer Vue senior.