Skip to content
This repository has been archived by the owner on Jan 1, 2025. It is now read-only.

Commit

Permalink
Avoid re-renders when setting atom to same value (#386)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #386

When we set an atom to the same value (based on reference equality), or we have redundant resets, we can avoid updating the state, re-evaluating downstream nodes, or re-rendering subscribing components.

Reviewed By: habond

Differential Revision: D21964833

fbshipit-source-id: 132b6870d35a4f209bb8ecb9e81d59dd3866397e
  • Loading branch information
drarmstr authored and facebook-github-bot committed Jun 26, 2020
1 parent e2d6b5b commit 845e0e4
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 1 deletion.
9 changes: 9 additions & 0 deletions src/recoil_values/Recoil_atom.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,15 @@ function baseAtom<T>(options: BaseAtomOptions<T>): RecoilState<T> {
): [TreeState, $ReadOnlySet<NodeKey>] {
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);
Expand Down
47 changes: 46 additions & 1 deletion src/recoil_values/__tests__/Recoil_atom-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(<AtomComponent />);

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;
Expand Down

0 comments on commit 845e0e4

Please sign in to comment.