Skip to content

Commit 85c1e85

Browse files
committed
Don't continuously observeRect on Popovers that are hidden
1 parent 85ebe4a commit 85c1e85

File tree

3 files changed

+119
-2
lines changed

3 files changed

+119
-2
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React, { useRef, useState, useCallback } from "react";
2+
import Popover from "@reach/popover";
3+
4+
let name = "Hidden";
5+
6+
function Example() {
7+
const ref = useRef(null);
8+
const [open, setOpen] = useState(false);
9+
const updateOpen = useCallback(
10+
(e) => {
11+
setOpen(e.target.checked);
12+
},
13+
[setOpen]
14+
);
15+
16+
return (
17+
<div>
18+
<textarea placeholder="resize me to move stuff around" />
19+
<label style={{ display: "inline-block" }}>
20+
<input ref={ref} type="checkbox" onChange={updateOpen} />
21+
Open popover
22+
</label>
23+
<Popover hidden={!open} targetRef={ref}>
24+
<div
25+
style={{
26+
backgroundColor: "#FFF",
27+
border: "1px solid #333",
28+
padding: "0 1em",
29+
borderRadius: "0.5em",
30+
maxWidth: "15em",
31+
}}
32+
>
33+
<p>
34+
Wow, popover content! It's still in the DOM, even when it's not
35+
visible.
36+
</p>
37+
<p>
38+
<i style={{ opacity: 0.8 }}>
39+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
40+
</i>
41+
</p>
42+
<p>
43+
<button>I should be the next tab</button>
44+
</p>
45+
</div>
46+
</Popover>
47+
<button>and then tab to me after that one</button>
48+
</div>
49+
);
50+
}
51+
52+
Example.story = { name };
53+
export const Comp = Example;
54+
export default { title: "Popover" };
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React, { useRef, useState, useCallback } from "react";
2+
import Popover from "@reach/popover";
3+
4+
let name = "Hidden (TS)";
5+
6+
function Example() {
7+
const ref = useRef<HTMLInputElement>(null);
8+
const [open, setOpen] = useState(false);
9+
const updateOpen = useCallback(
10+
(e: React.ChangeEvent<HTMLInputElement>) => {
11+
setOpen(e.target.checked);
12+
},
13+
[setOpen]
14+
);
15+
16+
return (
17+
<div>
18+
<textarea placeholder="resize me to move stuff around" />
19+
<label style={{ display: "inline-block" }}>
20+
<input ref={ref} type="checkbox" onChange={updateOpen} />
21+
Open popover
22+
</label>
23+
<Popover hidden={!open} targetRef={ref}>
24+
<div
25+
style={{
26+
backgroundColor: "#FFF",
27+
border: "1px solid #333",
28+
padding: "0 1em",
29+
borderRadius: "0.5em",
30+
maxWidth: "15em",
31+
}}
32+
>
33+
<p>
34+
Wow, popover content! It's still in the DOM, even when it's not
35+
visible.
36+
</p>
37+
<p>
38+
<i style={{ opacity: 0.8 }}>
39+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
40+
</i>
41+
</p>
42+
<p>
43+
<button>I should be the next tab</button>
44+
</p>
45+
</div>
46+
</Popover>
47+
<button>and then tab to me after that one</button>
48+
</div>
49+
);
50+
}
51+
52+
Example.story = { name };
53+
export const Comp = Example;
54+
export default { title: "Popover" };

packages/popover/src/index.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ export type PopoverProps = {
2828
children: React.ReactNode;
2929
targetRef: React.RefObject<HTMLElement>;
3030
position?: Position;
31+
/**
32+
* Render the popover markup, but hide it – used by MenuButton so that it
33+
* can have an `aria-controls` attribute even when its menu isn't open, and
34+
* used inside `Popover` as a hint that we can tell `useRect` to stop
35+
* observing for performance's sake.
36+
*/
37+
hidden?: boolean;
3138
/**
3239
* Testing this API so we might accept additional nodes that apps can use to
3340
* determine the position of the popover. One example where it may be useful
@@ -58,13 +65,14 @@ const PopoverImpl = forwardRef<HTMLDivElement, PopoverProps>(
5865
targetRef,
5966
position = positionDefault,
6067
unstable_observableRefs = [],
68+
hidden,
6169
...props
6270
},
6371
forwardedRef
6472
) {
6573
const popoverRef = useRef<HTMLDivElement>(null);
66-
const popoverRect = useRect(popoverRef);
67-
const targetRect = useRect(targetRef);
74+
const popoverRect = useRect(popoverRef, !hidden);
75+
const targetRect = useRect(targetRef, !hidden);
6876
const ref = useForkedRef(popoverRef, forwardedRef);
6977

7078
useSimulateTabNavigationForReactTree(targetRef, popoverRef);
@@ -73,6 +81,7 @@ const PopoverImpl = forwardRef<HTMLDivElement, PopoverProps>(
7381
<div
7482
data-reach-popover=""
7583
ref={ref}
84+
hidden={hidden}
7685
{...props}
7786
style={{
7887
position: "absolute",

0 commit comments

Comments
 (0)