Hone logo
Hone
Problems

Dynamic Data Loading with Async Vue Components

In modern web applications, it's common to fetch data or load complex components asynchronously to improve initial page load times and user experience. Vue.js provides a powerful mechanism for creating asynchronous components, allowing you to defer the loading of a component until it's actually needed. This challenge will test your ability to implement and manage asynchronous components in a Vue.js application using TypeScript.

Problem Description

Your task is to create a Vue component that dynamically loads another component asynchronously. This asynchronous component will simulate fetching data from an API and displaying it.

What needs to be achieved:

  1. Create a parent component that acts as a container. This component will manage the state that triggers the loading of the asynchronous child component.
  2. Create an asynchronous child component. This component should be defined using Vue's defineAsyncComponent API. It should simulate a network request (e.g., using setTimeout) before rendering its content.
  3. Handle loading and error states for the asynchronous component. The parent component should display a "Loading..." message while the child component is being fetched and an "Error loading component." message if the asynchronous loading fails.
  4. Use TypeScript for all component definitions and logic.

Key requirements:

  • The parent component should have a button or some user interaction that triggers the loading of the asynchronous component.
  • The asynchronous component should accept a prop (e.g., dataToDisplay) and render it.
  • The asynchronous component should have a simulated delay of at least 1 second using setTimeout.
  • Implement basic error handling for the asynchronous component loading.

Expected behavior:

When the user interacts with the parent component (e.g., clicks a button), the asynchronous component should start loading. The parent component should display a "Loading..." state. Once the asynchronous component has successfully loaded, it should be rendered, and its content should be visible. If an error occurs during the loading process, an error message should be displayed instead.

Edge cases to consider:

  • What happens if the simulated API request in the asynchronous component fails (you can simulate this by intentionally throwing an error in the setTimeout callback)?
  • How would you handle the case where the user triggers the loading multiple times before the first load completes? (For this challenge, you can assume a single trigger is sufficient, but it's good to be aware of.)

Examples

Example 1: Successful Load

Parent Component Template (Conceptual):

<div>
  <button @click="loadAsyncComponent">Load Data</button>
  <div v-if="componentLoaded">
    <AsyncDataDisplay :dataToDisplay="fetchedData" />
  </div>
  <div v-else-if="isLoading">Loading...</div>
  <div v-else-if="loadError">Error loading component.</div>
</div>

Async Component Logic (Conceptual):

// Inside defineAsyncComponent factory function
setTimeout(() => {
  resolve({
    template: `<div>Data: {{ dataToDisplay }}</div>`,
    props: ['dataToDisplay']
  });
}, 1000);

Explanation:

The user clicks the "Load Data" button. The parent component sets isLoading to true and componentLoaded to false. The AsyncDataDisplay component starts loading. After 1 second, the AsyncDataDisplay successfully resolves, and its template is rendered with the fetchedData. isLoading is set to false and componentLoaded to true.

Example 2: Error Load

Parent Component Template (Conceptual):

<div>
  <button @click="loadAsyncComponent">Load Data</button>
  <div v-if="componentLoaded">
    <AsyncDataDisplay :dataToDisplay="fetchedData" />
  </div>
  <div v-else-if="isLoading">Loading...</div>
  <div v-else-if="loadError">Error loading component.</div>
</div>

Async Component Logic (Conceptual):

// Inside defineAsyncComponent factory function
setTimeout(() => {
  // Simulate an error
  reject(new Error('API fetch failed'));
}, 1000);

Explanation:

The user clicks the "Load Data" button. The parent component sets isLoading to true. The AsyncDataDisplay component starts loading. After 1 second, the simulated API request within the defineAsyncComponent factory function rejects with an error. The parent component catches this error, sets isLoading to false, loadError to true, and displays the error message.

Constraints

  • Vue.js version 3.x must be used.
  • TypeScript must be used for component definitions and logic.
  • The simulated network delay should be a minimum of 1000ms (1 second).
  • The solution should be a single .vue file (or equivalent structure for parent/child components if demonstrating a larger project setup).
  • The asynchronous component must be defined using defineAsyncComponent.

Notes

  • You will need to simulate the data fetching logic within the defineAsyncComponent factory function.
  • Consider using the loadingComponent and errorComponent options of defineAsyncComponent for a more robust solution, although for this challenge, handling these states in the parent component is sufficient and demonstrates the core concept.
  • Think about how defineAsyncComponent returns a Promise. This is key to how Vue manages the loading and resolution.
  • The parent component will need to manage state variables to track isLoading, componentLoaded, and loadError.
Loading editor...
typescript