Execution — fw-03-reactivity-signals
Steps extracted from CONCEPTS.md. Read the concepts first; this file is the doing.
Record results in observation.md; tick checkpoints in verification.md.
3. Build order — mini-vue reactivity
reactive(obj)viaProxy— get/set traps.effect(fn)— a global "currently running effect" and a dependency map.- Dependency tracking:
track(target, key)on get,trigger(target, key)on set. ref(value)— the primitive-value case, and why it needs.value.computed(fn)— lazy, cached, and itself both a dependent and a dependency.watch(source, cb).- Cleanup: effects must drop stale dependencies on re-run.
- Nested effects — an effect stack, not a single global.
- Scheduling and batching: a microtask-flushed queue, deduplicated.
4. Build order — mini-signals
Then rebuild the same capability with a minimal signal API (signal, computed, effect,
batch). Deliberately do not reuse the Vue code. The point is to find out how much of it was
essential and how much was Vue-specific.
5. Failure Lab
- Dependency leak. Omit cleanup on re-run. Build a case where an effect depends on a branch it no longer reads, and keeps firing. This is the bug cleanup exists for.
- Infinite loop. An effect that writes a value it reads. Predict, then observe. Then design the guard — and note what legitimate patterns your guard forbids.
- Stale computed. Break the cache invalidation so a computed returns an old value. Explain why lazy caching is harder than it looks.
- Lost reactivity. Destructure a reactive object and lose tracking. Explain to a hypothetical junior in three sentences.
- Nested effect corruption. Use a single global "current effect" instead of a stack; watch the inner effect steal the outer's dependencies.
- Batching absence. 1,000 writes in a loop with no scheduler. Measure. Then batch.