Vue 3 Reactive Dependency Tracker
This challenge focuses on building a core concept of Vue's reactivity system: creating reactive dependencies. Understanding how Vue tracks and updates values based on their dependencies is fundamental to writing efficient and maintainable Vue applications. You will implement a simplified version of this mechanism.
Problem Description
Your task is to create a function that mimics Vue's ref and computed functionalities to establish reactive dependencies. You need to implement two core pieces:
myRef<T>(value: T): This function will take an initial value and return an object with avalueproperty. Thisvalueproperty should be reactive, meaning any changes to it can be tracked.myComputed<T>(getter: () => T): This function will take a getter function and return an object with avalueproperty. Thevalueproperty should be computed based on the getter. Crucially, if the getter depends on anymyRefvalues, themyComputed's value should automatically update whenever those dependencies change.
The goal is to ensure that when a myRef's value changes, any myComputed properties that depend on it are re-evaluated and their value property is updated accordingly.
Examples
Example 1: Basic Ref and Computed
import { myRef, myComputed } from './reactivity'; // Assume these are in a local file
const count = myRef(0);
const doubledCount = myComputed(() => count.value * 2);
console.log(doubledCount.value); // Output: 0
count.value = 5;
console.log(doubledCount.value); // Output: 10
Explanation:
Initially, count is 0, so doubledCount is computed as 0 * 2 = 0. When count.value is updated to 5, the myComputed property doubledCount detects the change in its dependency (count.value) and re-evaluates its getter, resulting in 5 * 2 = 10.
Example 2: Multiple Dependencies
import { myRef, myComputed } from './reactivity';
const firstName = myRef('John');
const lastName = myRef('Doe');
const fullName = myComputed(() => `${firstName.value} ${lastName.value}`);
console.log(fullName.value); // Output: John Doe
firstName.value = 'Jane';
console.log(fullName.value); // Output: Jane Doe
lastName.value = 'Smith';
console.log(fullName.value); // Output: Jane Smith
Explanation:
fullName depends on both firstName and lastName. When either firstName or lastName changes, fullName is recomputed to reflect the latest values.
Example 3: Computed Without Dependencies (Static)
import { myRef, myComputed } from './reactivity';
const staticValue = myComputed(() => 100);
console.log(staticValue.value); // Output: 100
// Even if other refs change, staticValue should not.
const unrelatedRef = myRef(5);
unrelatedRef.value = 10;
console.log(staticValue.value); // Output: 100
Explanation:
staticValue's getter does not access any reactive myRef properties. Therefore, it is computed only once and its value remains static, regardless of other reactive changes.
Constraints
- The
myReffunction must return an object with a writablevalueproperty. - The
myComputedfunction must return an object with a read-onlyvalueproperty. - The reactivity system should handle multiple
myComputedproperties depending on the samemyRef. - The reactivity system should handle a
myComputedproperty depending on multiplemyRefproperties. - The getter function for
myComputedwill not receive any arguments. - The core reactivity logic should be implemented in TypeScript.
Notes
- Think about how you will "track" which
myComputedproperties are currently "listening" to whichmyRefproperties. - Consider the lifecycle of a computed property: when does it need to be computed? When does it need to be recomputed?
- Vue's internal implementation uses Proxies for reactivity. For this challenge, you can use simple object property access and a mechanism to store and trigger updates.
- The goal is to demonstrate the dependency tracking and update mechanism, not necessarily to be as performant or robust as Vue's actual implementation.
- You will need to implement the
myRefandmyComputedfunctions yourself. The examples assume they are imported from a local file namedreactivity.ts.