Skip to content

Commit 1ebf202

Browse files
committed
fix: correct comment grammar, improve sidebar component display name and fixed potential memory leak issue in useNavigationState
1 parent 41e3879 commit 1ebf202

File tree

3 files changed

+27
-12
lines changed

3 files changed

+27
-12
lines changed

apps/site/components/withSidebar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const WithSidebar: FC<WithSidebarProps> = ({ navKeys, context, ...props }) => {
3636
useNavigationState('sidebar', sidebarRef);
3737

3838
const mappedSidebarItems =
39-
// If there's only a single navigation key, use it's sub-items
39+
// If there's only a single navigation key, use its sub-items
4040
// as our navigation.
4141
(navKeys.length === 1 ? sideNavigation[0][1].items : sideNavigation).map(
4242
([, { label, items }]) => ({

apps/site/hooks/client/useNavigationState.ts

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
'use client';
22

3-
import { useContext, useEffect } from 'react';
3+
import { useCallback, useContext, useEffect, useRef } from 'react';
44

55
import { NavigationStateContext } from '#site/providers/navigationStateProvider';
6-
import { debounce } from '#site/util/objects';
76

87
import type { RefObject } from 'react';
98

@@ -13,26 +12,40 @@ const useNavigationState = <T extends HTMLElement>(
1312
debounceTime = 300
1413
) => {
1514
const navigationState = useContext(NavigationStateContext);
15+
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
1616

17-
const handleScroll = debounce(() => {
18-
if (ref.current) {
19-
navigationState[id] = {
20-
x: ref.current.scrollLeft,
21-
y: ref.current.scrollTop,
22-
};
17+
const handleScroll = useCallback(() => {
18+
if (timeoutRef.current) {
19+
clearTimeout(timeoutRef.current);
2320
}
24-
}, debounceTime);
21+
22+
timeoutRef.current = setTimeout(() => {
23+
if (ref.current) {
24+
navigationState[id] = {
25+
x: ref.current.scrollLeft,
26+
y: ref.current.scrollTop,
27+
};
28+
}
29+
}, debounceTime);
30+
}, [id, ref, navigationState, debounceTime]);
2531

2632
useEffect(() => {
2733
const element = ref.current;
2834
if (element) {
2935
if (navigationState[id] && navigationState[id].y !== element.scrollTop) {
30-
element.scroll({ top: navigationState[id].y, behavior: 'instant' });
36+
element.scroll({ top: navigationState[id].y, behavior: 'auto' });
3137
}
3238

3339
element.addEventListener('scroll', handleScroll, { passive: true });
3440

35-
return () => element.removeEventListener('scroll', handleScroll);
41+
return () => {
42+
element.removeEventListener('scroll', handleScroll);
43+
// Clear any pending debounced calls
44+
if (timeoutRef.current) {
45+
clearTimeout(timeoutRef.current);
46+
timeoutRef.current = null;
47+
}
48+
};
3649
}
3750
// We need this effect to run only on mount
3851
// eslint-disable-next-line react-hooks/exhaustive-deps

packages/ui-components/src/Containers/Sidebar/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,6 @@ const SideBar = forwardRef<HTMLElement, PropsWithChildren<SidebarProps>>(
6161
}
6262
);
6363

64+
SideBar.displayName = 'SideBar';
65+
6466
export default SideBar;

0 commit comments

Comments
 (0)