Skip to content

Commit e1a42cf

Browse files
committed
wip
1 parent 706716d commit e1a42cf

File tree

2 files changed

+41
-9
lines changed

2 files changed

+41
-9
lines changed

packages/alpinejs/src/reactivity.js

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,21 @@ export function watch(getter, callback) {
6868
JSON.stringify(value)
6969

7070
if (! firstTime) {
71-
// We have to queue this watcher as a microtask so that
72-
// the watcher doesn't pick up its own dependencies.
73-
queueMicrotask(() => {
74-
callback(value, oldValue)
75-
76-
oldValue = value
77-
})
78-
} else {
79-
oldValue = value
71+
// For objects, always fire (deep watching may have detected nested changes).
72+
// For primitives, only fire if value actually changed.
73+
if (typeof value === 'object' || value !== oldValue) {
74+
// We have to queue this watcher as a microtask so that
75+
// the watcher doesn't pick up its own dependencies.
76+
let previousValue = oldValue
77+
78+
queueMicrotask(() => {
79+
callback(value, previousValue)
80+
})
81+
}
8082
}
8183

84+
oldValue = value
85+
8286
firstTime = false
8387
})
8488

tests/cypress/integration/magics/$watch.spec.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,34 @@ test('$watch ignores other dependencies',
150150
)
151151

152152

153+
test('$watch nested property does not fire when parent replaced but value unchanged',
154+
html`
155+
<div x-data="{ foo: { bar: { baz: 'hello' } }, callCount: 0 }" x-init="
156+
$watch('foo.bar.baz', value => { callCount++ });
157+
">
158+
<h1 x-text="foo.bar.baz"></h1>
159+
<span x-text="callCount"></span>
160+
161+
<button id="same" x-on:click="foo = { bar: { baz: 'hello' } }"></button>
162+
<button id="different" x-on:click="foo = { bar: { baz: 'world' } }"></button>
163+
</div>
164+
`,
165+
({ get }) => {
166+
get('h1').should(haveText('hello'))
167+
get('span').should(haveText('0'))
168+
169+
// Replace parent with same nested value - should NOT fire
170+
get('button#same').click()
171+
get('h1').should(haveText('hello'))
172+
get('span').should(haveText('0')) // callCount should still be 0
173+
174+
// Replace with different value - SHOULD fire
175+
get('button#different').click()
176+
get('h1').should(haveText('world'))
177+
get('span').should(haveText('1')) // callCount should be 1
178+
}
179+
)
180+
153181
test('deep $watch',
154182
html`
155183
<div x-data="{ foo: { bar: 'baz'}, bob: 'lob' }" x-init="

0 commit comments

Comments
 (0)