Skip to content

Commit 9bb7047

Browse files
committed
feat: 🎸 keep global state of all useLockBodyScroll hooks
This change will keep document body locked as long as at least one hook is enabled on the page. Maybe it makes sense to generalize this logic for other side-effect hooks. One such hook could be useBlurBody that blurs page - useful for modals and overlays.
1 parent fa6e9f3 commit 9bb7047

File tree

2 files changed

+42
-17
lines changed

2 files changed

+42
-17
lines changed

src/__stories__/useLockBodyScroll.story.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,34 @@ import ShowDocs from '../util/ShowDocs';
55

66
const Demo = () => {
77
const [locked, toggleLocked] = useToggle(false)
8-
98
useLockBodyScroll(locked);
109

1110
return (
1211
<div style={{height: '200vh'}}>
13-
<button onClick={() => toggleLocked()} style={{position: 'fixed', left: 0, right: 0}}>
12+
<button onClick={() => toggleLocked()} style={{position: 'fixed', left: 0}}>
1413
{locked ? 'Unlock' : 'Lock'}
1514
</button>
1615
</div>
1716
);
1817
};
1918

19+
const AnotherComponent = () => {
20+
const [locked, toggleLocked] = useToggle(false)
21+
useLockBodyScroll(locked);
22+
23+
return (
24+
<button onClick={() => toggleLocked()} style={{position: 'fixed', left: 0, top: 40}}>
25+
{locked ? 'Unlock' : 'Lock'}
26+
</button>
27+
);
28+
};
29+
2030
storiesOf('Side effects|useLockBodyScroll', module)
2131
.add('Docs', () => <ShowDocs md={require('../../docs/useLockBodyScroll.md')} />)
22-
.add('Demo', () =>
23-
<Demo/>
32+
.add('Demo', () => <Demo/>)
33+
.add('Two hooks on page', () =>
34+
<>
35+
<AnotherComponent />
36+
<Demo />
37+
</>
2438
)

src/useLockBodyScroll.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
1-
import {useRef, useEffect} from 'react';
2-
import {isClient} from './util';
3-
import useUnmount from './useUnmount';
1+
import {useEffect} from 'react';
42

5-
const useLockBodyScroll = (enabled: boolean = true) => {
6-
const originalOverflow = useRef(
7-
isClient ? window.getComputedStyle(document.body).overflow : 'visible'
8-
);
3+
let counter = 0;
4+
let originalOverflow: string | null = null;
5+
6+
const lock = () => {
7+
originalOverflow = window.getComputedStyle(document.body).overflow;
8+
document.body.style.overflow = 'hidden';
9+
};
10+
11+
const unlock = () => {
12+
document.body.style.overflow = originalOverflow;
13+
originalOverflow = null;
14+
};
915

10-
useEffect(() => {
11-
document.body.style.overflow = enabled ? "hidden" : originalOverflow.current;
12-
}, [enabled]);
16+
const increment = () => {
17+
counter++;
18+
if (counter === 1) lock();
19+
};
1320

14-
useUnmount(() => {
15-
document.body.style.overflow = originalOverflow.current
16-
});
21+
const decrement = () => {
22+
counter--;
23+
if (counter === 0) unlock();
24+
};
25+
26+
const useLockBodyScroll = (enabled: boolean = true) => {
27+
useEffect(() => enabled ? (increment(), decrement) : undefined, [enabled]);
1728
}
1829

1930
export default useLockBodyScroll;

0 commit comments

Comments
 (0)