Hone logo
Hone
Problems

Building a Suspense Component Wrapper in Vue.js (TypeScript)

This challenge focuses on creating a reusable Suspense component wrapper in Vue.js using TypeScript. The goal is to provide a mechanism to display a fallback component while asynchronous operations (like fetching data) are in progress, enhancing the user experience by preventing blank screens and providing visual feedback. This is a common pattern in modern web applications.

Problem Description

You are tasked with building a Suspense component that wraps another component and manages its loading state. The Suspense component should:

  1. Accept a default slot: This slot will contain the component that needs to be loaded asynchronously.
  2. Accept a fallback slot: This slot will contain a component to display while the default component is loading.
  3. Track loading state: The component should internally track whether the default component is currently loading. Assume the default component emits a loading event when it starts an asynchronous operation and a loaded event when the operation completes.
  4. Render appropriately:
    • While the default component is loading, render the content of the fallback slot.
    • Once the default component is loaded, render the content of the default slot.
  5. Provide a loading prop: This prop, when true, will force the fallback to be displayed, regardless of the loading state of the default component. This allows for pre-loading scenarios.

Expected Behavior:

The Suspense component should seamlessly switch between displaying the fallback and default components based on the loading state of the default component and the loading prop. The transition should be smooth and provide a clear indication to the user that something is happening.

Edge Cases to Consider:

  • What happens if the default component never emits a loaded event? (Consider a potential timeout or error handling). For this challenge, assume the component will eventually emit loaded.
  • What happens if the fallback component is not provided? (Default to rendering nothing).
  • What happens if the default component emits the loading event multiple times? (The fallback should remain displayed until loaded is emitted).
  • What happens if the loading prop is initially true? (The fallback should be displayed immediately).

Examples

Example 1:

Input:
<Suspense>
  <MyAsyncComponent />
  <template #fallback>Loading...</template>
</Suspense>

MyAsyncComponent emits 'loading' then 'loaded'
Output:
Initially: "Loading..."
After MyAsyncComponent emits 'loaded': MyAsyncComponent's content

Example 2:

Input:
<Suspense :loading="true">
  <MyAsyncComponent />
  <template #fallback>Please wait...</template>
</Suspense>

Output:
Immediately: "Please wait..."
(Regardless of MyAsyncComponent's loading state)

Example 3:

Input:
<Suspense>
  <MyAsyncComponent />
</Suspense>

Output:
Initially: Nothing (because no fallback is provided)
After MyAsyncComponent emits 'loaded': MyAsyncComponent's content

Constraints

  • The solution must be written in TypeScript.
  • The component should be a functional component using the <script setup> syntax.
  • The component should be reusable and not tightly coupled to any specific asynchronous operation.
  • The component should be performant; avoid unnecessary re-renders.
  • The loading prop should be a boolean.

Notes

  • Consider using Vue's reactivity system (ref) to manage the loading state.
  • Pay close attention to how the slots are rendered and when.
  • Think about how to handle the events emitted by the default component.
  • This is a simplified version of Vue's built-in <Suspense> component. The goal is to understand the underlying principles.
  • Focus on the core functionality of displaying the fallback while loading and switching to the default component when loaded. Error handling and more advanced features are not required for this challenge.
Loading editor...
typescript