diff --git a/src/recoil_values/Recoil_atom.js b/src/recoil_values/Recoil_atom.js index 60c17e80d..97913dc9c 100644 --- a/src/recoil_values/Recoil_atom.js +++ b/src/recoil_values/Recoil_atom.js @@ -263,6 +263,15 @@ function baseAtom(options: BaseAtomOptions): RecoilState { ): [TreeState, $ReadOnlySet] { initAtom(store, state, 'set'); + // Only update if setting a new value + if ( + state.atomValues.has(key) + ? newValue === state.atomValues.get(key)?.contents + : newValue instanceof DefaultValue + ) { + return [state, new Set()]; + } + if (__DEV__) { if (options.dangerouslyAllowMutability !== true) { deepFreezeValue(newValue); diff --git a/src/recoil_values/__tests__/Recoil_atom-test.js b/src/recoil_values/__tests__/Recoil_atom-test.js index ab44f38c0..2fdf0dc5e 100644 --- a/src/recoil_values/__tests__/Recoil_atom-test.js +++ b/src/recoil_values/__tests__/Recoil_atom-test.js @@ -17,7 +17,11 @@ const { getRecoilValueAsLoadable, setRecoilValue, } = require('../../core/Recoil_RecoilValueInterface'); -const {useRecoilTransactionObserver} = require('../../hooks/Recoil_Hooks'); +const { + useRecoilState, + useRecoilTransactionObserver, + useResetRecoilState, +} = require('../../hooks/Recoil_Hooks'); const { ReadsAtom, componentThatReadsAndWritesAtom, @@ -89,6 +93,47 @@ describe('Valid values', () => { }); }); +test("Updating with same value doesn't rerender", () => { + const myAtom = atom({key: 'atom same value rerender', default: 'DEFAULT'}); + + let setAtom; + let resetAtom; + let renders = 0; + function AtomComponent() { + renders++; + const [value, setValue] = useRecoilState(myAtom); + const resetValue = useResetRecoilState(myAtom); + setAtom = setValue; + resetAtom = resetValue; + return value; + } + expect(renders).toEqual(0); + const c = renderElements(); + + expect(renders).toEqual(3); + expect(c.textContent).toEqual('DEFAULT'); + + act(() => setAtom('SET')); + expect(renders).toEqual(4); + expect(c.textContent).toEqual('SET'); + + act(() => setAtom('SET')); + expect(renders).toEqual(4); + expect(c.textContent).toEqual('SET'); + + act(() => setAtom('CHANGE')); + expect(renders).toEqual(5); + expect(c.textContent).toEqual('CHANGE'); + + act(resetAtom); + expect(renders).toEqual(6); + expect(c.textContent).toEqual('DEFAULT'); + + act(resetAtom); + expect(renders).toEqual(6); + expect(c.textContent).toEqual('DEFAULT'); +}); + describe('Effects', () => { test('effect', () => { let inited = false;