Skip to content

Commit 7bfe748

Browse files
committed
Remove infinite render detection
1 parent 794e4c1 commit 7bfe748

File tree

5 files changed

+7
-59
lines changed

5 files changed

+7
-59
lines changed

.changeset/shiny-spiders-swim.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'jotai-x': patch
3+
---
4+
5+
PERF: Remove infinite render detection (causing performance issues in development)

README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ const { useUserValue, useUserSet, useUserState, UserProvider } =
8585
// Optional derived atoms
8686
intro: atom((get) => `My name is ${get(atoms.name)}`),
8787
}),
88-
infiniteRenderDetectionLimit: 100, // Optional render detection limit
8988
}
9089
);
9190
```
@@ -98,7 +97,6 @@ Available options:
9897
delay?: number;
9998
effect?: React.ComponentType;
10099
extend?: (atoms: Atoms) => DerivedAtoms;
101-
infiniteRenderDetectionLimit?: number;
102100
}
103101
```
104102

@@ -390,7 +388,7 @@ The store-based atom hooks provide more flexibility when working with external a
390388

391389
## Troubleshooting
392390

393-
### Infinite Render Detection
391+
### Infinite Renders
394392

395393
When using value hooks with selectors, ensure they are memoized:
396394

packages/jotai-x/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ const { useUserValue, useUserSet, useUserState, UserProvider } =
8585
// Optional derived atoms
8686
intro: atom((get) => `My name is ${get(atoms.name)}`),
8787
}),
88-
infiniteRenderDetectionLimit: 100, // Optional render detection limit
8988
}
9089
);
9190
```
@@ -98,7 +97,6 @@ Available options:
9897
delay?: number;
9998
effect?: React.ComponentType;
10099
extend?: (atoms: Atoms) => DerivedAtoms;
101-
infiniteRenderDetectionLimit?: number;
102100
}
103101
```
104102

@@ -390,7 +388,7 @@ The store-based atom hooks provide more flexibility when working with external a
390388

391389
## Troubleshooting
392390

393-
### Infinite Render Detection
391+
### Infinite Renders
394392

395393
When using value hooks with selectors, ensure they are memoized:
396394

packages/jotai-x/src/createAtomStore.spec.tsx

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -142,16 +142,6 @@ describe('createAtomStore', () => {
142142
);
143143
};
144144

145-
const BadSelectorRenderer = () => {
146-
const arr0 = useMyTestStoreStore().useArrValue((v) => v[0]);
147-
return <div>{arr0}</div>;
148-
};
149-
150-
const BadSelectorRenderer2 = () => {
151-
const arr0 = useMyTestStoreValue('arr', { selector: (v) => v[0] });
152-
return <div>{arr0}</div>;
153-
};
154-
155145
const Buttons = () => {
156146
const store = useMyTestStoreStore();
157147
return (
@@ -268,26 +258,6 @@ describe('createAtomStore', () => {
268258
expect(getByText('arrNum: ava')).toBeInTheDocument();
269259
expect(getByText('arrNumWithDeps: ava')).toBeInTheDocument();
270260
});
271-
272-
it('Throw error if user does not memoize selector', () => {
273-
expect(() =>
274-
render(
275-
<MyTestStoreProvider>
276-
<BadSelectorRenderer />
277-
</MyTestStoreProvider>
278-
)
279-
).toThrow();
280-
});
281-
282-
it('Throw error is user does memoize selector 2', () => {
283-
expect(() =>
284-
render(
285-
<MyTestStoreProvider>
286-
<BadSelectorRenderer2 />
287-
</MyTestStoreProvider>
288-
)
289-
).toThrow();
290-
});
291261
});
292262

293263
describe('single provider', () => {

packages/jotai-x/src/createAtomStore.ts

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,6 @@ export interface CreateAtomStoreOptions<
493493
delay?: UseAtomOptions['delay'];
494494
effect?: React.FC;
495495
extend?: (atomsWithoutExtend: StoreAtomsWithoutExtend<T>) => E;
496-
infiniteRenderDetectionLimit?: number;
497496
suppressWarnings?: boolean;
498497
}
499498

@@ -520,7 +519,6 @@ export const createAtomStore = <
520519
delay: delayRoot,
521520
effect,
522521
extend,
523-
infiniteRenderDetectionLimit = 100_000,
524522
suppressWarnings,
525523
}: CreateAtomStoreOptions<T, E, N>
526524
): AtomStoreApi<T, E, N> => {
@@ -584,8 +582,6 @@ export const createAtomStore = <
584582
return store ?? contextStore;
585583
};
586584

587-
let renderCount = 0;
588-
589585
const useAtomValueWithStore: UseAtomValueFn = (
590586
atomConfig,
591587
store,
@@ -594,25 +590,6 @@ export const createAtomStore = <
594590
equalityFnOrDeps,
595591
deps
596592
) => {
597-
// If selector/equalityFn are not memoized, infinite loop will occur.
598-
if (process.env.NODE_ENV !== 'production' && infiniteRenderDetectionLimit) {
599-
renderCount += 1;
600-
if (renderCount > infiniteRenderDetectionLimit) {
601-
throw new Error(
602-
`
603-
use<Key>Value/useValue/use<StoreName>Value has rendered ${infiniteRenderDetectionLimit} times in the same render.
604-
It is very likely to have fallen into an infinite loop.
605-
That is because you do not memoize the selector/equalityFn function param.
606-
Please wrap them with useCallback or configure the deps array correctly.`
607-
);
608-
}
609-
// We need to use setTimeout instead of useEffect here, because when infinite loop happens,
610-
// the effect (fired in the next micro task) will execute before the rerender.
611-
setTimeout(() => {
612-
renderCount = 0;
613-
});
614-
}
615-
616593
const options = convertScopeShorthand(optionsOrScope);
617594
selector ??= identity;
618595
const equalityFn =

0 commit comments

Comments
 (0)