Skip to content

Commit 35a7af8

Browse files
committed
Small nits
We use Object.is to check whether the snapshot value has been updated, so we should also use it to check whether the value is cached.
1 parent 6a47428 commit 35a7af8

File tree

4 files changed

+31
-32
lines changed

4 files changed

+31
-32
lines changed

packages/react-reconciler/src/ReactFiberHooks.new.js

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,10 +1291,7 @@ function mountSyncExternalStore<T>(
12911291
if (__DEV__) {
12921292
if (!didWarnUncachedGetSnapshot) {
12931293
const cachedSnapshot = getSnapshot();
1294-
if (
1295-
!(Number.isNaN(nextSnapshot) && Number.isNaN(cachedSnapshot)) &&
1296-
nextSnapshot !== cachedSnapshot
1297-
) {
1294+
if (!is(nextSnapshot, cachedSnapshot)) {
12981295
console.error(
12991296
'The result of getSnapshot should be cached to avoid an infinite loop',
13001297
);
@@ -1367,10 +1364,7 @@ function updateSyncExternalStore<T>(
13671364
if (__DEV__) {
13681365
if (!didWarnUncachedGetSnapshot) {
13691366
const cachedSnapshot = getSnapshot();
1370-
if (
1371-
!(Number.isNaN(nextSnapshot) && Number.isNaN(cachedSnapshot)) &&
1372-
nextSnapshot !== cachedSnapshot
1373-
) {
1367+
if (!is(nextSnapshot, cachedSnapshot)) {
13741368
console.error(
13751369
'The result of getSnapshot should be cached to avoid an infinite loop',
13761370
);

packages/react-reconciler/src/ReactFiberHooks.old.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,7 +1290,8 @@ function mountSyncExternalStore<T>(
12901290
nextSnapshot = getSnapshot();
12911291
if (__DEV__) {
12921292
if (!didWarnUncachedGetSnapshot) {
1293-
if (nextSnapshot !== getSnapshot()) {
1293+
const cachedSnapshot = getSnapshot();
1294+
if (!is(nextSnapshot, cachedSnapshot)) {
12941295
console.error(
12951296
'The result of getSnapshot should be cached to avoid an infinite loop',
12961297
);
@@ -1362,7 +1363,8 @@ function updateSyncExternalStore<T>(
13621363
const nextSnapshot = getSnapshot();
13631364
if (__DEV__) {
13641365
if (!didWarnUncachedGetSnapshot) {
1365-
if (nextSnapshot !== getSnapshot()) {
1366+
const cachedSnapshot = getSnapshot();
1367+
if (!is(nextSnapshot, cachedSnapshot)) {
13661368
console.error(
13671369
'The result of getSnapshot should be cached to avoid an infinite loop',
13681370
);

packages/use-sync-external-store/src/__tests__/useSyncExternalStoreShared-test.js

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -587,28 +587,34 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
587587
);
588588
});
589589

590-
describe('extra features implemented in user-space', () => {
591-
test('Selector can return NaN without infinite loop warning', async () => {
592-
const store = createExternalStore({nan: 'not a number'});
590+
test('getSnapshot can return NaN without infinite loop warning', async () => {
591+
const store = createExternalStore('not a number');
593592

594-
function App() {
595-
const selectedNaN = useSyncExternalStoreWithSelector(
596-
store.subscribe,
597-
store.getState,
598-
null,
599-
s => parseInt(s.nan, 10),
600-
);
601-
return <Text text={selectedNaN.toString()} />;
602-
}
593+
function App() {
594+
const value = useSyncExternalStore(store.subscribe, () =>
595+
parseInt(store.getState(), 10),
596+
);
597+
return <Text text={value} />;
598+
}
603599

604-
const container = document.createElement('div');
605-
const root = createRoot(container);
600+
const container = document.createElement('div');
601+
const root = createRoot(container);
606602

607-
await act(() => root.render(<App />));
603+
// Initial render that reads a snapshot of NaN. This is OK because we use
604+
// Object.is algorithm to compare values.
605+
await act(() => root.render(<App />));
606+
expect(container.textContent).toEqual('NaN');
608607

609-
expect(container.textContent).toEqual('NaN');
610-
});
608+
// Update to real number
609+
await act(() => store.set(123));
610+
expect(container.textContent).toEqual('123');
611611

612+
// Update back to NaN
613+
await act(() => store.set('not a number'));
614+
expect(container.textContent).toEqual('NaN');
615+
});
616+
617+
describe('extra features implemented in user-space', () => {
612618
// The selector implementation uses the lazy ref initialization pattern
613619
// @gate !(enableUseRefAccessWarning && __DEV__)
614620
test('memoized selectors are only called once per update', async () => {

packages/use-sync-external-store/src/useSyncExternalStoreShimClient.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,8 @@ export function useSyncExternalStore<T>(
5757
const value = getSnapshot();
5858
if (__DEV__) {
5959
if (!didWarnUncachedGetSnapshot) {
60-
const valueShouldBeCached = getSnapshot();
61-
if (
62-
!(Number.isNaN(value) && Number.isNaN(valueShouldBeCached)) &&
63-
value !== valueShouldBeCached
64-
) {
60+
const cachedValue = getSnapshot();
61+
if (!is(value, cachedValue)) {
6562
console.error(
6663
'The result of getSnapshot should be cached to avoid an infinite loop',
6764
);

0 commit comments

Comments
 (0)