Hone logo
Hone
Problems

Vue Watcher Implementation Challenge

This challenge focuses on building a fundamental reactive system in Vue.js: the watcher. You will implement a mechanism that allows you to react to changes in specific data properties within a Vue component. Understanding watchers is crucial for managing side effects and performing asynchronous operations based on data updates.

Problem Description

Your task is to implement a simplified version of Vue's reactivity watcher. You need to create a function that takes a Vue component instance and a callback function as arguments. This watcher should monitor a specific reactive property within the component's data. When the monitored property changes, the provided callback function should be executed.

Key Requirements:

  • The watcher should be able to monitor a single reactive data property.
  • The callback function should receive the new value and the old value of the monitored property as arguments.
  • The watcher should be able to be deactivated.

Expected Behavior:

When a data property that is being watched changes its value, the associated callback function should be invoked immediately with the new and old values.

Edge Cases to Consider:

  • What happens if the monitored property doesn't exist in the component's data?
  • What happens if the watcher is deactivated and the property changes?
  • Ensure the watcher correctly handles initial property values.

Examples

Example 1:

Component Setup:

import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const counter = ref(0);

    const increment = () => {
      counter.value++;
    };

    // Assume we have a mechanism to attach a watcher later
    // For this example, imagine a 'watch' function is available

    return {
      counter,
      increment,
    };
  },
});

Watcher Implementation (Conceptual):

// Assume this is your implemented watcher function
function watch(componentInstance: any, propertyName: string, callback: (newValue: any, oldValue: any) => void): () => void {
    // ... implementation details ...
    // Returns an unwatch function
}

// Usage within a component's setup or lifecycle hooks:
// const unwatch = watch(this, 'counter', (newVal, oldVal) => {
//   console.log(`Counter changed from ${oldVal} to ${newVal}`);
// });

// To stop watching:
// unwatch();

Scenario:

  1. Component is initialized with counter as 0.
  2. A watcher is set up for counter with a callback that logs the change.
  3. increment() is called, changing counter to 1.

Expected Output in Console:

Counter changed from 0 to 1

Example 2:

Component Setup:

import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const message = ref('Hello');

    const updateMessage = (newMessage: string) => {
      message.value = newMessage;
    };

    return {
      message,
      updateMessage,
    };
  },
});

Watcher Implementation (Conceptual):

// Assume your 'watch' function is available and works as described

Scenario:

  1. Component is initialized with message as 'Hello'.
  2. A watcher is set up for message with a callback that logs the change.
  3. updateMessage('Vue is awesome!') is called.

Expected Output in Console:

Message changed from Hello to Vue is awesome!

Example 3: Deactivation

Component Setup:

import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const isActive = ref(true);

    const toggleActive = () => {
      isActive.value = !isActive.value;
    };

    return {
      isActive,
      toggleActive,
    };
  },
});

Watcher Implementation (Conceptual):

// Assume your 'watch' function is available and returns an unwatch function

Scenario:

  1. Component is initialized with isActive as true.
  2. A watcher is set up for isActive with a callback that logs the change.
  3. The watcher is deactivated using the returned unwatch() function.
  4. toggleActive() is called, changing isActive to false.

Expected Output in Console:

(No output from the watcher's callback, as it has been deactivated)

Constraints

  • The watcher implementation should be written in TypeScript.
  • Your implementation should focus on monitoring a single reactive property defined within the component's data or setup function.
  • You are expected to understand Vue 3's Composition API (setup function and ref) for accessing component data.
  • Your solution should be efficient and avoid unnecessary re-renders or computations.

Notes

  • Consider how Vue itself makes data reactive. You don't need to implement the entire Vue reactivity system from scratch, but you should leverage the reactive properties provided by Vue.
  • Think about how to access the component's data and how to trigger the callback when a change is detected.
  • The watch function you implement should mimic the signature and behavior of Vue's built-in watch function for a single property.
  • Pay attention to how you store the oldValue and newValue to pass them to the callback.
Loading editor...
typescript