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:
- Component is initialized with
counteras0. - A watcher is set up for
counterwith a callback that logs the change. increment()is called, changingcounterto1.
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:
- Component is initialized with
messageas'Hello'. - A watcher is set up for
messagewith a callback that logs the change. 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:
- Component is initialized with
isActiveastrue. - A watcher is set up for
isActivewith a callback that logs the change. - The watcher is deactivated using the returned
unwatch()function. toggleActive()is called, changingisActivetofalse.
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
dataorsetupfunction. - You are expected to understand Vue 3's Composition API (
setupfunction andref) 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
watchfunction you implement should mimic the signature and behavior of Vue's built-inwatchfunction for a single property. - Pay attention to how you store the
oldValueandnewValueto pass them to the callback.