Advanced Composables

Preview — 3 of 10 questions

What is required for a component with an async setup() to work correctly with <Suspense>?

javascript
<!-- AsyncUserProfile.vue  async setup component -->
<script setup>
const props = defineProps({ userId: String })

// Top-level await makes setup async
const user = await fetchUser(props.userId)
const posts = await fetchUserPosts(props.userId)
</script>

<template>
  <div>{{ user.name }}: {{ posts.length }} posts</div>
</template>

<!-- Parent component -->
<template>
  <Suspense>
    <template #default>
      <AsyncUserProfile :userId="userId" />
    </template>
    <template #fallback>
      <div>Loading user profile...</div>
    </template>
  </Suspense>
</template>
AThe component must be wrapped with defineAsyncComponent
BThe parent must use <Suspense> and the child must export an asyncData function
CThe setup() function must use await at the top level, and the component must be wrapped in <Suspense> in the parent
D<Suspense> only works with useAsyncData from Nuxt, not standalone Vue

How do you handle errors from async setup components within <Suspense>?

javascript
<!-- ErrorBoundary.vue -->
<script setup>
import { ref, onErrorCaptured } from 'vue'

const error = ref(null)

onErrorCaptured((err, instance, info) => {
  error.value = err
  return false // Prevents error propagation to parent
})
</script>

<template>
  <div v-if="error" class="error-boundary">
    <h2>Something went wrong</h2>
    <p>{{ error.message }}</p>
  </div>
  <slot v-else />
</template>

<!-- Usage -->
<template>
  <ErrorBoundary>
    <Suspense>
      <template #default>
        <AsyncComponent />
      </template>
      <template #fallback>
        <LoadingSpinner />
      </template>
    </Suspense>
  </ErrorBoundary>
</template>
AUse try/catch in the parent's setup()
BWrap <Suspense> in a component that implements onErrorCaptured — creating an error boundary
CUse onErrorCaptured hook in the parent wrapping component
DUse the error named slot of <Suspense>

What pattern allows a composable to accept reactive arguments that can be either a plain value or a ref?

javascript
import { computed, toValue, type MaybeRefOrGetter } from 'vue'

// Flexible composable — accepts ref, computed, getter, or plain value
function useDouble(count: MaybeRefOrGetter<number>) {
  return computed(() => toValue(count) * 2)
}

// All of these work:
const a = useDouble(5)                    // plain value
const b = useDouble(ref(5))              // ref
const c = useDouble(computed(() => 5))   // computed ref
const d = useDouble(() => someRef.value) // getter function

// Pre-Vue 3.3 equivalent using unref():
import { unref } from 'vue'

function useDouble(count) {
  return computed(() => unref(count) * 2)
  // unref(x) = isRef(x) ? x.value : x (does not handle getter functions)
}
AUsing toValue() (Vue 3.3+) or unref() — the MaybeRefOrGetter pattern
BUsing computed to wrap every argument inside the composable
CUsing shallowRef on every argument inside the composable
DUsing TypeScript generics to constrain the argument type at compile time

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.