Skip to content

Commit

Permalink
fix: dedupe subscribers in flushPending
Browse files Browse the repository at this point in the history
  • Loading branch information
dmaskasky committed Nov 17, 2024
1 parent 8083b5c commit 8c9258f
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 4 deletions.
9 changes: 7 additions & 2 deletions src/vanilla/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,16 @@ const flushPending = (pending: Pending) => {
}
while (pending[1].size || pending[2].size) {
pending[0].clear()
const atomStates = new Set(pending[1].values())
const atomListeners = new Set<() => void>()
for (const aState of pending[1].values()) {
if (aState.m) {
aState.m.l.forEach((listener) => atomListeners.add(listener))
}
}
pending[1].clear()
const functions = new Set(pending[2])
pending[2].clear()
atomStates.forEach((atomState) => atomState.m?.l.forEach(call))
atomListeners.forEach(call)
functions.forEach(call)
}
if (hasError) {
Expand Down
24 changes: 22 additions & 2 deletions tests/vanilla/dependency.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { expect, it, vi } from 'vitest'
import { atom, createStore } from 'jotai/vanilla'
import type {
INTERNAL_DevStoreRev4,
INTERNAL_PrdStore,
} from 'jotai/vanilla/store'

it('can propagate updates with async atom chains', async () => {
const store = createStore()
Expand Down Expand Up @@ -349,16 +353,32 @@ it('can read sync derived atom in write without initializing', () => {

it.only('batches sync writes', () => {
const a = atom(1)
const b = atom(2)
a.debugLabel = 'a'
const b = atom(1)
b.debugLabel = 'b'
const fetch = vi.fn((va, vb) => va * 10 + vb)
const c = atom((get) => fetch(get(a), get(b)))

Check failure on line 360 in tests/vanilla/dependency.test.tsx

View workflow job for this annotation

GitHub Actions / test_matrix (4.0.5)

Parameter 'va' implicitly has an 'any' type.

Check failure on line 360 in tests/vanilla/dependency.test.tsx

View workflow job for this annotation

GitHub Actions / test_matrix (4.0.5)

Parameter 'vb' implicitly has an 'any' type.

Check failure on line 360 in tests/vanilla/dependency.test.tsx

View workflow job for this annotation

GitHub Actions / test_matrix (3.9.7)

Parameter 'va' implicitly has an 'any' type.

Check failure on line 360 in tests/vanilla/dependency.test.tsx

View workflow job for this annotation

GitHub Actions / test_matrix (3.9.7)

Parameter 'vb' implicitly has an 'any' type.

Check failure on line 360 in tests/vanilla/dependency.test.tsx

View workflow job for this annotation

GitHub Actions / test_matrix (3.8.3)

Parameter 'va' implicitly has an 'any' type.

Check failure on line 360 in tests/vanilla/dependency.test.tsx

View workflow job for this annotation

GitHub Actions / test_matrix (3.8.3)

Parameter 'vb' implicitly has an 'any' type.
c.debugLabel = 'c'
const d = atom(null, (_, set) => {
set(a, (v) => ++v)
set(b, (v) => ++v)
})
const store = createStore()
d.debugLabel = 'd'
const store = createStore() as INTERNAL_DevStoreRev4 & INTERNAL_PrdStore
const getAtomState = store.dev4_get_internal_weak_map().get
store.sub(a, () => {})
store.sub(b, () => {})
const cListener = vi.fn()
store.sub(c, cListener)
store.sub(d, () => {})
const aState = getAtomState(a) as any
aState.label = 'a'
const bState = getAtomState(b) as any
bState.label = 'b'
const cState = getAtomState(c) as any
cState.label = 'c'
const dState = getAtomState(d) as any
dState.label = 'd'
cListener.mockClear()
fetch.mockClear()
store.set(d)
Expand Down

0 comments on commit 8c9258f

Please sign in to comment.