Skip to content

Commit b0192bc

Browse files
committed
Additional test and cleaning up stale values
1 parent 97653a7 commit b0192bc

2 files changed

Lines changed: 70 additions & 3 deletions

File tree

packages/components/src/spectrum/TabPanels.test.tsx

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import React, { useState } from 'react';
2-
import { render, screen } from '@testing-library/react';
1+
import React, { useEffect, useState } from 'react';
2+
import { render, screen, waitFor } from '@testing-library/react';
33
import {
44
defaultTheme,
55
Item,
@@ -20,6 +20,22 @@ function Counter({ label }: { label: string }) {
2020
);
2121
}
2222

23+
function OnMountUnmount({
24+
onMount,
25+
onUnmount,
26+
}: {
27+
onMount: () => void;
28+
onUnmount: () => void;
29+
}) {
30+
useEffect(() => {
31+
onMount();
32+
return () => {
33+
onUnmount();
34+
};
35+
}, [onMount, onUnmount]);
36+
return null;
37+
}
38+
2339
describe('TabPanels', () => {
2440
it('should not persist panel state by default when switching tabs', () => {
2541
render(
@@ -152,4 +168,51 @@ describe('TabPanels', () => {
152168
'background-color: red'
153169
);
154170
});
171+
172+
it('should still unmount a panel that is not in the tree when using keepMounted', () => {
173+
const onMount = jest.fn();
174+
const onUnmount = jest.fn();
175+
const { rerender } = render(
176+
<Provider theme={defaultTheme}>
177+
<Tabs aria-label="test">
178+
<TabList>
179+
<Item key="1">Tab 1</Item>
180+
<Item key="2">Tab 2</Item>
181+
</TabList>
182+
<DHCTabPanels>
183+
<Item key="1">
184+
<Counter label="foo" />
185+
</Item>
186+
<Item key="2">
187+
<OnMountUnmount onMount={onMount} onUnmount={onUnmount} />
188+
</Item>
189+
</DHCTabPanels>
190+
</Tabs>
191+
</Provider>
192+
);
193+
194+
waitFor(() => expect(onMount).toHaveBeenCalledTimes(1));
195+
expect(onUnmount).toHaveBeenCalledTimes(0);
196+
197+
rerender(
198+
<Provider theme={defaultTheme}>
199+
<Tabs aria-label="test">
200+
<TabList>
201+
<Item key="1">Tab 1</Item>
202+
<Item key="2">Tab 2</Item>
203+
</TabList>
204+
<DHCTabPanels>
205+
<Item key="1">
206+
<Counter label="foo" />
207+
</Item>
208+
<Item key="2">
209+
<Counter label="bar" />
210+
</Item>
211+
</DHCTabPanels>
212+
</Tabs>
213+
</Provider>
214+
);
215+
216+
waitFor(() => expect(onUnmount).toHaveBeenCalledTimes(1));
217+
});
155218
});

packages/components/src/spectrum/TabPanels.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ export function DHCTabPanels<T extends object>(
3636

3737
const portalNodes = useMemo(() => {
3838
const nodes: JSX.Element[] = [];
39+
const nextNodeMap = new Map<Key, HtmlPortalNode>(); // Keep track of the portals we use so we can clean up stale portals
3940
if (!keepMounted) {
41+
portalNodeMap.current = nextNodeMap;
4042
return nodes;
4143
}
4244
React.Children.forEach(children, child => {
@@ -53,15 +55,17 @@ export function DHCTabPanels<T extends object>(
5355
style: 'display: contents',
5456
},
5557
});
56-
portalNodeMap.current.set(child.key, portal);
5758
}
59+
nextNodeMap.set(child.key, portal);
5860
nodes.push(
5961
<InPortal node={portal} key={child.key}>
6062
{child.props.children}
6163
</InPortal>
6264
);
6365
});
6466

67+
portalNodeMap.current = nextNodeMap;
68+
6569
return nodes;
6670
}, [children, keepMounted]);
6771

0 commit comments

Comments
 (0)