Skip to content

Commit 65c860e

Browse files
committed
Added debounded method to improve performance and optimised code
1 parent e2e5018 commit 65c860e

File tree

1 file changed

+65
-38
lines changed

1 file changed

+65
-38
lines changed

web-server/src/content/Service/SystemLogs.tsx

Lines changed: 65 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,25 @@ const SystemLogs = memo(({ serviceName }: { serviceName?: ServiceNames }) => {
2121
const containerRef = useRef<HTMLDivElement>(null);
2222
const showScrollDownButton = useBoolState(false);
2323
const [searchQuery, setSearchQuery] = useState('');
24+
const [debouncedSearchQuery, setDebouncedSearchQuery] = useState('');
2425
const [currentMatch, setCurrentMatch] = useState(0);
2526
const [totalMatches, setTotalMatches] = useState(0);
2627
const [highlightedElements, setHighlightedElements] = useState<HTMLElement[]>([]);
2728
const currentHighlightRef = useRef<HTMLElement | null>(null);
2829
const isInitialLoad = useRef(true);
30+
const isSearchingRef = useRef(false);
31+
const currentMatchRef = useRef(0);
32+
const totalMatchesRef = useRef(0);
33+
const highlightedElementsRef = useRef<HTMLElement[]>([]);
34+
const isNavigatingRef = useRef(false);
35+
36+
// Debounce search query updates
37+
useEffect(() => {
38+
const timer = setTimeout(() => {
39+
setDebouncedSearchQuery(searchQuery);
40+
}, 300);
41+
return () => clearTimeout(timer);
42+
}, [searchQuery]);
2943

3044
const scrollToBottom = useCallback(() => {
3145
if (containerRef.current) {
@@ -53,80 +67,94 @@ const SystemLogs = memo(({ serviceName }: { serviceName?: ServiceNames }) => {
5367

5468
const handleSearch = useCallback((query: string) => {
5569
setSearchQuery(query);
70+
isSearchingRef.current = !!query;
5671

57-
// Reset states only when query is empty or below a threshold
5872
if (!query || query.length < 3) {
5973
setCurrentMatch(0);
74+
currentMatchRef.current = 0;
6075
setTotalMatches(0);
76+
totalMatchesRef.current = 0;
6177
setHighlightedElements([]);
78+
highlightedElementsRef.current = [];
6279
updateHighlight(null);
6380
return;
6481
}
65-
66-
// Let the effect handle DOM updates
6782
}, [updateHighlight]);
6883

6984
useLayoutEffect(() => {
70-
if (!searchQuery || searchQuery.length < 3) return;
85+
if (!debouncedSearchQuery || debouncedSearchQuery.length < 3) return;
7186

7287
const elements = Array.from(
7388
containerRef.current?.querySelectorAll('span[style*="background-color: yellow"]') ?? []
7489
) as HTMLElement[];
7590

7691
setHighlightedElements(elements);
77-
setTotalMatches(elements.length);
78-
setCurrentMatch(elements.length ? 1 : 0);
79-
80-
if (elements.length) {
81-
updateHighlight(elements[0]);
82-
elements[0].scrollIntoView({ behavior: 'smooth', block: 'center' });
92+
highlightedElementsRef.current = elements;
93+
const newTotalMatches = elements.length;
94+
setTotalMatches(newTotalMatches);
95+
totalMatchesRef.current = newTotalMatches;
96+
97+
if (currentMatchRef.current === 0) {
98+
setCurrentMatch(newTotalMatches ? 1 : 0);
99+
currentMatchRef.current = newTotalMatches ? 1 : 0;
83100
}
84-
}, [searchQuery, logs, updateHighlight]);
85-
101+
}, [debouncedSearchQuery]);
86102

87103
const handleNavigate = useCallback((direction: 'prev' | 'next') => {
88-
if (highlightedElements.length === 0) return;
89-
90-
let newIndex = currentMatch;
91-
if (direction === 'next') {
92-
newIndex = currentMatch < totalMatches ? currentMatch + 1 : 1;
93-
} else {
94-
newIndex = currentMatch > 1 ? currentMatch - 1 : totalMatches;
95-
}
104+
if (highlightedElementsRef.current.length === 0 || isNavigatingRef.current) return;
105+
106+
isNavigatingRef.current = true;
107+
requestAnimationFrame(() => {
108+
let newIndex = currentMatchRef.current;
109+
if (direction === 'next') {
110+
newIndex = currentMatchRef.current < totalMatchesRef.current ? currentMatchRef.current + 1 : 1;
111+
} else {
112+
newIndex = currentMatchRef.current > 1 ? currentMatchRef.current - 1 : totalMatchesRef.current;
113+
}
96114

97-
setCurrentMatch(newIndex);
98-
const element = highlightedElements[newIndex - 1];
99-
if (element) {
100-
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
101-
updateHighlight(element);
102-
}
103-
}, [currentMatch, totalMatches, highlightedElements, updateHighlight]);
115+
setCurrentMatch(newIndex);
116+
currentMatchRef.current = newIndex;
117+
const element = highlightedElementsRef.current[newIndex - 1];
118+
if (element) {
119+
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
120+
updateHighlight(element);
121+
}
122+
isNavigatingRef.current = false;
123+
});
124+
}, [updateHighlight]);
104125

105126
useEffect(() => {
106127
if (!loading && logs.length && containerRef.current && isInitialLoad.current) {
107128
isInitialLoad.current = false;
108129
requestAnimationFrame(() => {
109-
containerRef.current?.scrollTo({
110-
top: containerRef.current.scrollHeight,
111-
behavior: 'auto'
112-
});
130+
if (containerRef.current) {
131+
containerRef.current.scrollTo({
132+
top: containerRef.current.scrollHeight,
133+
behavior: 'auto'
134+
});
135+
}
113136
});
114137
}
115138
}, [loading, logs]);
116139

117140
const renderLogs = useCallback(() => {
118141
return logs.map((log, index) => {
119142
const parsedLog = parseLogLine(log);
120-
if (!parsedLog) {
121-
return <PlainLog log={log} index={index} key={index} searchQuery={searchQuery} />;
122-
}
123-
return <FormattedLog log={parsedLog} index={index} key={index} searchQuery={searchQuery} />;
143+
return (
144+
<div key={index}>
145+
{!parsedLog ? (
146+
<PlainLog log={log} index={index} searchQuery={debouncedSearchQuery} />
147+
) : (
148+
<FormattedLog log={parsedLog} index={index} searchQuery={debouncedSearchQuery} />
149+
)}
150+
</div>
151+
);
124152
});
125-
}, [logs, searchQuery]);
153+
}, [logs, debouncedSearchQuery]);
126154

127155
return (
128156
<ErrorBoundary
129-
FallbackComponent={({ error }) => (
157+
FallbackComponent={({ error }: { error: Error }) => (
130158
<SystemLogsErrorFallback error={error} serviceName={serviceName} />
131159
)}
132160
>
@@ -174,5 +202,4 @@ const SystemLogs = memo(({ serviceName }: { serviceName?: ServiceNames }) => {
174202
);
175203
});
176204

177-
178205
export { SystemLogs };

0 commit comments

Comments
 (0)