diff --git a/src/vanilla/store.ts b/src/vanilla/store.ts index 49b3599fd1..f02b8ceb9a 100644 --- a/src/vanilla/store.ts +++ b/src/vanilla/store.ts @@ -528,7 +528,21 @@ export const createStore = () => { mountDependencies(atom, atomState, prevAtomState?.d) } const mounted = mountedMap.get(atom) - mounted?.l.forEach((listener) => listener()) + if ( + mounted && + !( + // TODO This seems pretty hacky. Hope to fix it. + // Maybe we could `mountDependencies` in `setAtomState`? + ( + prevAtomState && + !hasPromiseAtomValue(prevAtomState) && + (isEqualAtomValue(prevAtomState, atomState) || + isEqualAtomError(prevAtomState, atomState)) + ) + ) + ) { + mounted.l.forEach((listener) => listener()) + } } else if (__DEV__) { console.warn('[Bug] no atom state to flush') } diff --git a/tests/vanilla/store.test.tsx b/tests/vanilla/store.test.tsx new file mode 100644 index 0000000000..c4d45dba39 --- /dev/null +++ b/tests/vanilla/store.test.tsx @@ -0,0 +1,22 @@ +import { atom, createStore } from 'jotai/vanilla' + +it('should not fire subscription if primitive atom value is the same', async () => { + const store = createStore() + const countAtom = atom(0) + const callback = jest.fn() + store.sub(countAtom, callback) + const calledTimes = callback.mock.calls.length + store.set(countAtom, 0) + expect(callback).toBeCalledTimes(calledTimes) +}) + +it('should not fire subscription if derived atom value is the same', async () => { + const store = createStore() + const countAtom = atom(0) + const derivedAtom = atom((get) => get(countAtom) * 0) + const callback = jest.fn() + store.sub(derivedAtom, callback) + const calledTimes = callback.mock.calls.length + store.set(countAtom, 1) + expect(callback).toBeCalledTimes(calledTimes) +})