Hone logo
Hone
Problems

Vue 3 Functional Components: Building a Reusable Counter

This challenge will test your understanding of Vue 3's functional components. You will create a simple, reusable counter component that can be controlled externally. This is a common pattern for building flexible UI elements in Vue.

Problem Description

You need to create a Vue 3 functional component named FunctionalCounter. This component should display a counter value and provide a way to increment it.

Key Requirements:

  • Functional Component: The component must be implemented as a functional component in Vue 3, using the setup function with a props argument.
  • Display Counter: The component should display the current value of the counter.
  • Event Emission: When the counter is incremented, the component should emit a custom event named incremented. This event should carry the new counter value as its payload.
  • External Control (Props): The initial value of the counter should be configurable via a prop named initialValue.
  • No Internal State Management: The FunctionalCounter component itself should not maintain its own internal data or ref for the counter value. The counter's value should be managed by its parent component.

Expected Behavior:

  1. A parent component will render FunctionalCounter and pass an initialValue prop.
  2. The FunctionalCounter will display this initialValue.
  3. The FunctionalCounter will render a button.
  4. When the button is clicked, the FunctionalCounter will emit an incremented event, incrementing the counter value by 1 from the perspective of the parent component.

Edge Cases:

  • What happens if initialValue is not provided? It should default to 0.

Examples

Example 1: Basic Usage

Parent Component (Vue Template):

<template>
  <div>
    <FunctionalCounter :initialValue="startCount" @incremented="handleIncrement" />
    <p>Current Total: {{ startCount }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import FunctionalCounter from './FunctionalCounter.vue'; // Assume this is the file containing your functional component

const startCount = ref(5);

const handleIncrement = (newValue: number) => {
  startCount.value = newValue;
};
</script>

FunctionalCounter Component (Vue Template - conceptual):

<template>
  <div>
    <p>Counter: {{ currentCounterValue }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

Output (After clicking "Increment" button 3 times):

Counter: 8
Current Total: 8

Explanation: The parent starts with startCount at 5. The FunctionalCounter displays 5 initially. Each click on "Increment" in the functional component emits an incremented event with the new value. The parent's handleIncrement function updates startCount, which is then reflected in both the parent's display and the functional component's display (as it will receive the updated value on re-render or if it were somehow linked, though the problem states no internal state). Correction: The functional component itself does not know the current value directly; it only knows how to trigger the increment. The parent manages the actual count. The functional component will visually display the value it's told to display via props, which gets updated when the parent's state changes. The key is that the functional component triggers the change in the parent.

Example 2: Default Initial Value

Parent Component (Vue Template):

<template>
  <div>
    <FunctionalCounter @incremented="handleIncrement" />
    <p>Current Total: {{ startCount }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import FunctionalCounter from './FunctionalCounter.vue';

const startCount = ref(0); // Parent expects it to start at 0 if no prop is passed

const handleIncrement = (newValue: number) => {
  startCount.value = newValue;
};
</script>

Output (After clicking "Increment" button 2 times):

Current Total: 2

Explanation: Since initialValue is not passed, the FunctionalCounter uses its default of 0. The parent's startCount is updated accordingly.

Constraints

  • The FunctionalCounter component must be a functional component.
  • The component must be written in TypeScript.
  • The incremented event must be emitted correctly with the next integer value.
  • The initialValue prop must be an integer.

Notes

  • Recall how to define props and emit events in a Vue 3 functional component's setup function.
  • Consider how to handle the event listener for the button click within a functional component.
  • The core of this challenge is understanding that functional components receive props and context, and they trigger actions in their parent via event emissions, rather than managing their own state.
  • The display of the "current counter value" within the functional component will be derived from the initialValue prop passed down from the parent. When the parent's state changes (due to an incremented event), the new value will be passed as a prop to the FunctionalCounter, which will then display that new value.
Loading editor...
typescript