Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/atom-set-undefined.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/store': patch
---

Fix `atom.set(undefined)` being ignored. A mutable atom now takes `undefined` as its new value and compares it like any other, so setting `undefined` again does not notify subscribers. Only an internal `_update()` call made with no argument is still skipped.
12 changes: 9 additions & 3 deletions packages/store/src/atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,10 @@ export function createAtom<T>(
activeSub = atom
++cycle
atom.depsTail = undefined
} else if (getValue === undefined) {
} else if (arguments.length === 0) {
Comment thread
mbret marked this conversation as resolved.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
// Mutable atoms can be marked dirty by the reactive graph, but they should
// never be recomputed without an explicit value/updater.
// never be recomputed without an explicit value/updater. Check the argument
// count rather than `undefined`, which `set(undefined)` passes as a value.
return false
}
if (isComputed) {
Expand All @@ -219,7 +220,12 @@ export function createAtom<T>(
: getValue === undefined && isComputed
? getter(oldValue)
: getValue!
if (oldValue === undefined || !compare(oldValue, newValue)) {
// A computed atom treats an `undefined` snapshot as not computed yet. A
// mutable atom's `undefined` is a value like any other.
if (
(isComputed && oldValue === undefined) ||
!compare(oldValue, newValue)
) {
atom._snapshot = newValue
return true
}
Expand Down
15 changes: 14 additions & 1 deletion packages/store/tests/store.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, test, vi } from 'vitest'
// import { Store } from '../src/index'
import { createStore } from '../src'
import { createAtom, createStore } from '../src'

describe('store', () => {
test(`should set the initial value`, () => {
Expand Down Expand Up @@ -116,4 +116,17 @@ describe('store', () => {
expect(atom._update()).toBe(false)
expect(store.state).toEqual({ pageIndex: 1 })
})

test('mutable atom can be set to undefined', () => {
const atom = createAtom<number | undefined>(1)
const fn = vi.fn()
atom.subscribe(fn)

atom.set(undefined)
atom.set(undefined)

expect(atom.get()).toBeUndefined()
expect(fn).toHaveBeenCalledTimes(1)
expect(fn).toHaveBeenCalledWith(undefined)
})
})