Skip to content

Commit a1d01ca

Browse files
Copilothotlong
andcommitted
fix: address code review feedback — fix LCP metric, debounce isolation, crossFade, auto-sync delay
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 22ec19d commit a1d01ca

3 files changed

Lines changed: 33 additions & 17 deletions

File tree

packages/react/src/hooks/useOffline.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,13 +261,12 @@ export function useOffline(config: OfflineConfig = {}): OfflineResult {
261261
}
262262
}, [enabled, queue]);
263263

264-
// Auto-sync when coming back online
264+
// Auto-sync when coming back online (short stabilization delay)
265265
useEffect(() => {
266266
if (!enabled || !isOnline || queue.length === 0) return;
267-
const retryInterval = syncConfigRef.current?.retryInterval ?? 5000;
268267
const timer = setTimeout(() => {
269268
void sync();
270-
}, retryInterval);
269+
}, 100);
271270
return () => clearTimeout(timer);
272271
// Only trigger on isOnline changes, not on every queue change
273272
// eslint-disable-next-line react-hooks/exhaustive-deps

packages/react/src/hooks/usePageTransition.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,13 @@ export function usePageTransition(config: PageTransitionConfig = {}): PageTransi
165165
const enterStyle: React.CSSProperties = { ...baseStyle };
166166
const exitStyle: React.CSSProperties = { ...baseStyle };
167167

168+
// When crossFade is enabled, both the entering and exiting pages
169+
// should overlap and transition opacity simultaneously.
168170
if (crossFade) {
169-
enterStyle.opacity = 0;
170-
enterStyle.animationName = undefined; // let the class handle it
171+
enterStyle.position = 'absolute';
172+
enterStyle.inset = '0';
173+
exitStyle.position = 'absolute';
174+
exitStyle.inset = '0';
171175
}
172176

173177
return {

packages/react/src/hooks/usePerformance.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -91,23 +91,26 @@ const DEFAULTS = {
9191
// Helpers
9292
// ---------------------------------------------------------------------------
9393

94-
function getWebVital(name: string): number | null {
94+
function getFCP(): number | null {
9595
if (typeof performance === 'undefined' || !performance.getEntriesByType) return null;
9696
try {
9797
const entries = performance.getEntriesByType('paint');
98-
const entry = entries.find((e) => e.name === name);
98+
const entry = entries.find((e) => e.name === 'first-contentful-paint');
9999
return entry ? Math.round(entry.startTime) : null;
100100
} catch {
101101
return null;
102102
}
103103
}
104104

105105
function getLCP(): number | null {
106-
return getWebVital('largest-contentful-paint');
107-
}
108-
109-
function getFCP(): number | null {
110-
return getWebVital('first-contentful-paint');
106+
if (typeof performance === 'undefined' || !performance.getEntriesByType) return null;
107+
try {
108+
const entries = performance.getEntriesByType('largest-contentful-paint');
109+
const entry = entries.length > 0 ? entries[entries.length - 1] : undefined;
110+
return entry ? Math.round(entry.startTime) : null;
111+
} catch {
112+
return null;
113+
}
111114
}
112115

113116
// ---------------------------------------------------------------------------
@@ -205,23 +208,33 @@ export function usePerformance(userConfig: PerformanceConfig = {}): PerformanceR
205208
}, []);
206209

207210
const debounceMs = config.debounceMs;
208-
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
211+
const timersRef = useRef<Set<ReturnType<typeof setTimeout>>>(new Set());
209212

210213
const debounce = useCallback(
211214
<T extends (...args: unknown[]) => void>(fn: T): T => {
215+
let timer: ReturnType<typeof setTimeout> | null = null;
212216
const debounced = (...args: unknown[]) => {
213-
if (timerRef.current) clearTimeout(timerRef.current);
214-
timerRef.current = setTimeout(() => fn(...args), debounceMs);
217+
if (timer) {
218+
clearTimeout(timer);
219+
timersRef.current.delete(timer);
220+
}
221+
timer = setTimeout(() => {
222+
fn(...args);
223+
if (timer) timersRef.current.delete(timer);
224+
}, debounceMs);
225+
timersRef.current.add(timer);
215226
};
216227
return debounced as unknown as T;
217228
},
218229
[debounceMs],
219230
);
220231

221-
// Cleanup debounce timer
232+
// Cleanup all debounce timers
222233
useEffect(() => {
234+
const timers = timersRef.current;
223235
return () => {
224-
if (timerRef.current) clearTimeout(timerRef.current);
236+
timers.forEach((t) => clearTimeout(t));
237+
timers.clear();
225238
};
226239
}, []);
227240

0 commit comments

Comments
 (0)