Skip to content

Commit cc4d121

Browse files
authored
Ensure Collection commits its updated information when nodes are removed (#5735)
1 parent 46ae331 commit cc4d121

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

packages/react-aria-components/src/Collection.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ export class Document<T, C extends BaseCollection<T> = BaseCollection<T>> extend
605605

606606
this.dirtyNodes.clear();
607607

608-
if (this.mutatedNodes.size) {
608+
if (this.mutatedNodes.size || this.collectionMutated) {
609609
let collection = this.getMutableCollection();
610610
for (let element of this.mutatedNodes) {
611611
if (element.isConnected) {
@@ -664,6 +664,7 @@ export function useCachedChildren<T extends object>(props: CachedChildrenOptions
664664
let {children, items, idScope, addIdAndValue, dependencies = []} = props;
665665

666666
// Invalidate the cache whenever the parent value changes.
667+
// eslint-disable-next-line react-hooks/exhaustive-deps
667668
let cache = useMemo(() => new WeakMap(), dependencies);
668669
return useMemo(() => {
669670
if (items && typeof children === 'function') {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {ListBoxItem} from '../src/ListBox';
2+
import React from 'react';
3+
import {render} from '@testing-library/react';
4+
import {useCollection} from '../src/Collection';
5+
6+
7+
const CollectionTest = (props) => {
8+
const result = useCollection(props);
9+
props.spyCollection.current = result.collection;
10+
return <>{result.portal}</>;
11+
};
12+
13+
const renderItems = (items, spyCollection) => (
14+
<CollectionTest spyCollection={spyCollection}>
15+
{items.map((item) => <ListBoxItem key={item} />)}
16+
</CollectionTest>
17+
);
18+
19+
describe('Collection', () => {
20+
it('should be frozen even in case of empty initial collection', () => {
21+
let spyCollection = {};
22+
render(renderItems([], spyCollection));
23+
expect(spyCollection.current.frozen).toBe(true);
24+
});
25+
26+
it('should have correct firstKey, lastKey and should be frozen after all items are deleted', () => {
27+
let spyCollection = {};
28+
const {rerender} = render(renderItems(['a'], spyCollection));
29+
rerender(renderItems([], spyCollection));
30+
expect(spyCollection.current.frozen).toBe(true);
31+
expect(spyCollection.current.firstKey).toBe(null);
32+
expect(spyCollection.current.lastKey).toBe(null);
33+
});
34+
});

0 commit comments

Comments
 (0)