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
setupfunction with apropsargument. - 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
FunctionalCountercomponent itself should not maintain its own internaldataorreffor the counter value. The counter's value should be managed by its parent component.
Expected Behavior:
- A parent component will render
FunctionalCounterand pass aninitialValueprop. - The
FunctionalCounterwill display thisinitialValue. - The
FunctionalCounterwill render a button. - When the button is clicked, the
FunctionalCounterwill emit anincrementedevent, incrementing the counter value by 1 from the perspective of the parent component.
Edge Cases:
- What happens if
initialValueis 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
FunctionalCountercomponent must be a functional component. - The component must be written in TypeScript.
- The
incrementedevent must be emitted correctly with the next integer value. - The
initialValueprop must be an integer.
Notes
- Recall how to define props and emit events in a Vue 3 functional component's
setupfunction. - 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
initialValueprop passed down from the parent. When the parent's state changes (due to anincrementedevent), the new value will be passed as a prop to theFunctionalCounter, which will then display that new value.