瀏覽代碼

Expose Alpine.watch

Caleb Porzio 1 年之前
父節點
當前提交
b7bfd88633
共有 3 個文件被更改,包括 42 次插入25 次删除
  1. 2 1
      packages/alpinejs/src/alpine.js
  2. 11 24
      packages/alpinejs/src/magics/$watch.js
  3. 29 0
      packages/alpinejs/src/reactivity.js

+ 2 - 1
packages/alpinejs/src/alpine.js

@@ -1,4 +1,4 @@
-import { setReactivityEngine, disableEffectScheduling, reactive, effect, release, raw } from './reactivity'
+import { setReactivityEngine, disableEffectScheduling, reactive, effect, release, raw, watch } from './reactivity'
 import { mapAttributes, directive, setPrefix as prefix, prefix as prefixed } from './directives'
 import { start, addRootSelector, addInitSelector, closestRoot, findClosest, initTree, destroyTree, interceptInit } from './lifecycle'
 import { onElRemoved, onAttributeRemoved, onAttributesAdded, mutateDom, deferMutations, flushAndStopDeferringMutations, startObservingMutations, stopObservingMutations } from './mutation'
@@ -73,6 +73,7 @@ let Alpine = {
     cloneNode, // INTERNAL
     bound,
     $data,
+    watch,
     walk,
     data,
     bind,

+ 11 - 24
packages/alpinejs/src/magics/$watch.js

@@ -1,34 +1,21 @@
 import { magic } from '../magics'
+import { effect, release } from '../reactivity'
 
-magic('watch', (el, { evaluateLater, effect }) => (key, callback) => {
+magic('watch', (el, { evaluateLater, cleanup }) => (key, callback) => {
     let evaluate = evaluateLater(key)
 
-    let firstTime = true
+    let getter = () => {
+        let value
 
-    let oldValue
+        evaluate(i => value = i)
 
-    let effectReference = effect(() => evaluate(value => {
-        // JSON.stringify touches every single property at any level enabling deep watching
-        JSON.stringify(value)
+        return value
+    }
 
-        if (! firstTime) {
-            // We have to queue this watcher as a microtask so that
-            // the watcher doesn't pick up its own dependencies.
-            queueMicrotask(() => {
-                callback(value, oldValue)
+    let unwatch = watch(getter, () => {
 
-                oldValue = value
-            })
-        } else {
-            oldValue = value
-        }
+    })
 
-        firstTime = false
-    }))
-
-    // We want to remove this effect from the list of effects
-    // stored on an element. Livewire uses that list to
-    // "re-run" Alpine effects after a page load. A "watcher"
-    // shuldn't be re-run like that. It will cause infinite loops.
-    el._x_effects.delete(effectReference)
+    cleanup(unwatch)
 })
+

+ 29 - 0
packages/alpinejs/src/reactivity.js

@@ -56,6 +56,35 @@ export function elementBoundEffect(el) {
     return [wrappedEffect, () => { cleanup() }]
 }
 
+export function watch(getter, callback) {
+    let firstTime = true
+
+    let oldValue
+
+    let effectReference = effect(() => {
+        let value = getter()
+
+        // JSON.stringify touches every single property at any level enabling deep watching
+        JSON.stringify(value)
+
+        if (! firstTime) {
+            // We have to queue this watcher as a microtask so that
+            // the watcher doesn't pick up its own dependencies.
+            queueMicrotask(() => {
+                callback(value, oldValue)
+
+                oldValue = value
+            })
+        } else {
+            oldValue = value
+        }
+
+        firstTime = false
+    })
+
+    return () => release(effectReference)
+}
+
 export {
     release,
     reactive,