Hone logo
Hone
Problems

Dynamically Instantiating Vue Components with Props

This challenge focuses on the fundamental Vue.js concept of dynamically creating and rendering component instances. You will learn how to programmatically create a component and pass data to it, a common requirement for building flexible and interactive user interfaces.

Problem Description

Your task is to create a Vue 3 component that acts as a dynamic component renderer. This renderer should be capable of accepting a component definition and a set of props, and then rendering an instance of that component with the provided props.

Key Requirements:

  • The renderer component must accept two primary props:
    • component: This prop will receive the Vue component definition (e.g., imported component object).
    • propsData: This prop will be an object containing the key-value pairs to be passed as props to the dynamically rendered component.
  • The renderer component should use Vue's built-in <component :is="..." /> dynamic component feature to render the component prop.
  • The propsData should be correctly bound and passed to the dynamically rendered component.

Expected Behavior:

When the renderer component is used, it should display the component prop with the propsData applied. For example, if a Button component is passed as component and { text: 'Click Me', disabled: false } is passed as propsData, the rendered Button should display "Click Me" and be enabled.

Edge Cases to Consider:

  • What happens if component is null or undefined? The renderer should ideally render nothing.
  • What happens if propsData is an empty object? The dynamic component should be rendered without any props.
  • What if the component prop is not a valid Vue component definition? The behavior might be undefined or error-prone, but your implementation should aim for graceful handling if possible (though for this challenge, assume valid component definitions).

Examples

Example 1:

// Parent Component Template:
<template>
  <div>
    <DynamicRenderer :component="MyButton" :propsData="{ text: 'Submit', onClick: handleClick }" />
  </div>
</template>

// MyButton Component Definition:
<script setup lang="ts">
defineProps<{
  text: string;
  onClick?: () => void;
}>();
</script>
<template>
  <button @click="onClick">{{ text }}</button>
</template>

// Parent Component Script:
<script setup lang="ts">
import { ref } from 'vue';
import DynamicRenderer from './DynamicRenderer.vue'; // Assuming your renderer is in this file
import MyButton from './MyButton.vue';

const handleClick = () => {
  alert('Button clicked!');
};
</script>

Output:
A button with the text "Submit" will be rendered. Clicking it will trigger an alert.

Explanation:
The `DynamicRenderer` receives the `MyButton` component and a `propsData` object. It uses `<component :is="MyButton" v-bind="propsData" />` to render the `MyButton` with the specified `text` and `onClick` props.

Example 2:

// Parent Component Template:
<template>
  <div>
    <DynamicRenderer :component="GreetingMessage" :propsData="{ name: 'Alice' }" />
    <DynamicRenderer :component="GreetingMessage" :propsData="{ name: 'Bob' }" />
  </div>
</template>

// GreetingMessage Component Definition:
<script setup lang="ts">
defineProps<{
  name: string;
}>();
</script>
<template>
  <p>Hello, {{ name }}!</p>
</template>

// Parent Component Script:
<script setup lang="ts">
import DynamicRenderer from './DynamicRenderer.vue';
import GreetingMessage from './GreetingMessage.vue';
</script>

Output:
<p>Hello, Alice!</p>
<p>Hello, Bob!</p>

Explanation:
Two instances of `GreetingMessage` are rendered by separate `DynamicRenderer` instances, each receiving different `propsData` for the `name` prop.

Example 3: (Edge Case: No Props)

// Parent Component Template:
<template>
  <div>
    <DynamicRenderer :component="SimpleMessage" />
  </div>
</template>

// SimpleMessage Component Definition:
<script setup lang="ts">
// This component has no props
</script>
<template>
  <span>This is a simple message.</span>
</template>

// Parent Component Script:
<script setup lang="ts">
import DynamicRenderer from './DynamicRenderer.vue';
import SimpleMessage from './SimpleMessage.vue';
</script>

Output:
<span>This is a simple message.</span>

Explanation:
When `propsData` is not provided (or is an empty object), the `SimpleMessage` component is rendered without any props, as expected.

Constraints

  • The solution must be implemented using Vue 3 and TypeScript.
  • The DynamicRenderer component should have a clear and concise implementation.
  • Avoid using external libraries for dynamic component rendering; rely on Vue's core features.
  • The solution should be performant and not introduce unnecessary overhead.

Notes

  • Consider how you will pass the propsData object to the dynamic component. Vue's v-bind directive is particularly useful here.
  • You will need to define the DynamicRenderer component in a .vue file and export it for use in other components.
  • The <component> element in Vue is key to solving this problem. Refer to the Vue documentation for its usage with the :is attribute.
Loading editor...
typescript