diff --git a/packages/use-sync-external-store/src/__tests__/useSyncExternalStoreShared-test.js b/packages/use-sync-external-store/src/__tests__/useSyncExternalStoreShared-test.js
index 1488a8aa3de6c..b9099022423f2 100644
--- a/packages/use-sync-external-store/src/__tests__/useSyncExternalStoreShared-test.js
+++ b/packages/use-sync-external-store/src/__tests__/useSyncExternalStoreShared-test.js
@@ -624,6 +624,44 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
expect(container.textContent).toEqual('NaN');
});
+ test('selector is not called when snaphot has not changed', async () => {
+ const store = createExternalStore({a: 0});
+
+ function selector(state) {
+ Scheduler.log('Selector');
+ return state.a;
+ }
+
+ function isEqual(a, b) {
+ return a === b;
+ }
+
+ function App() {
+ Scheduler.log('App');
+ const a = useSyncExternalStoreWithSelector(
+ store.subscribe,
+ store.getState,
+ null,
+ selector,
+ isEqual,
+ );
+ return ;
+ }
+
+ const container = document.createElement('div');
+ const root = createRoot(container);
+ await act(() => root.render());
+ assertLog(['App', 'Selector', 'A0']);
+
+ await act(() => store.set(store.getState()));
+ await act(() => store.set({a: 0}));
+ assertLog(['Selector']);
+
+ await act(() => store.set(store.getState()));
+ await act(() => store.set(store.getState()));
+ assertLog([]);
+ });
+
describe('extra features implemented in user-space', () => {
// The selector implementation uses the lazy ref initialization pattern
// @gate !(enableUseRefAccessWarning && __DEV__)
diff --git a/packages/use-sync-external-store/src/useSyncExternalStoreWithSelector.js b/packages/use-sync-external-store/src/useSyncExternalStoreWithSelector.js
index 5b04ae892c875..1dbfd74f2c235 100644
--- a/packages/use-sync-external-store/src/useSyncExternalStoreWithSelector.js
+++ b/packages/use-sync-external-store/src/useSyncExternalStoreWithSelector.js
@@ -93,6 +93,7 @@ export function useSyncExternalStoreWithSelector(
// to React that the selections are conceptually equal, and we can bail
// out of rendering.
if (isEqual !== undefined && isEqual(prevSelection, nextSelection)) {
+ memoizedSnapshot = nextSnapshot;
return prevSelection;
}