Hone logo
Hone
Problems

Implementing a Custom onUnmounted Hook in Vue 3 with TypeScript

Vue 3's Composition API provides powerful tools for managing component logic. While onMounted is readily available, you might encounter scenarios where you need a more granular control over side effects that should run after a component is unmounted. This challenge focuses on creating a custom hook that replicates the functionality of an onUnmounted hook, allowing you to register cleanup functions for when a component is destroyed.

Problem Description

Your task is to create a reusable Vue 3 Composition API hook, useOnUnmounted, written in TypeScript. This hook should accept a callback function as an argument. This callback function should be executed precisely once, right before the component that uses this hook is unmounted from the DOM. This is crucial for cleaning up resources, unsubscribing from event listeners, or performing any other necessary actions to prevent memory leaks or unexpected behavior.

Key Requirements:

  • Hook Signature: The hook should have the signature useOnUnmounted(callback: () => void).
  • Execution Timing: The provided callback function must execute only when the component is unmounted.
  • Multiple Calls: The hook should gracefully handle multiple calls within the same component, ensuring each registered callback is executed.
  • TypeScript Support: The hook must be written in TypeScript and properly typed.

Expected Behavior:

When a component using useOnUnmounted is about to be removed from the DOM, all callbacks registered via useOnUnmounted within that component should be invoked.

Edge Cases:

  • A component might call useOnUnmounted multiple times.
  • A component might be unmounted immediately after mounting (e.g., due to conditional rendering).

Examples

Example 1:

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useOnUnmounted } from './useOnUnmounted'; // Assuming your hook is in this file

const message = ref('Component mounted!');

const cleanupTask = () => {
  console.log('Component is unmounting. Performing cleanup...');
  // Simulate cleaning up a resource
  message.value = 'Component cleaned up!';
};

useOnUnmounted(cleanupTask);

onMounted(() => {
  console.log('Component has mounted.');
});
</script>

<template>
  <div>{{ message }}</div>
</template>

Explanation:

When this component is rendered and then later unmounted, the cleanupTask function will be called, logging "Component is unmounting. Performing cleanup..." and updating the message ref.

Example 2:

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

const counter = ref(0);

const increment = () => {
  counter.value++;
  console.log('Incremented:', counter.value);
};

// Registering multiple cleanup functions
useOnUnmounted(() => {
  console.log('First unmount cleanup.');
});

useOnUnmounted(() => {
  console.log('Second unmount cleanup. Counter was:', counter.value);
});

// Simulate an interval that needs to be cleared
const intervalId = setInterval(increment, 1000);

useOnUnmounted(() => {
  console.log('Clearing interval...');
  clearInterval(intervalId);
});
</script>

<template>
  <div>Counter: {{ counter }}</div>
</template>

Explanation:

When this component is unmounted, the following will happen in order:

  1. "First unmount cleanup." will be logged.
  2. "Second unmount cleanup. Counter was: [current counter value]" will be logged.
  3. "Clearing interval..." will be logged.
  4. The setInterval will be cleared, stopping further increments.

Constraints

  • The hook must be implemented using Vue 3's Composition API.
  • The implementation should not rely on any third-party libraries for core functionality.
  • The callback function provided to the hook will not receive any arguments.
  • The hook should be compatible with <script setup> syntax.

Notes

Consider how Vue's lifecycle hooks work and how you can leverage existing Composition API functions to achieve the desired behavior. Think about how to store and manage the callbacks that need to be executed upon unmounting. You'll likely want to use onUnmounted from Vue itself internally.

Loading editor...
typescript