perf(parcel-sync): use useDeferredValue for UAT search input
React's useDeferredValue lets the input update immediately while deferring the expensive filter (3186 items) to a lower priority. Removes the setTimeout debounce in favor of React's built-in concurrent rendering scheduler. Input stays responsive. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect, useCallback, useMemo, useRef } from "react";
|
import { useState, useEffect, useCallback, useMemo, useRef, useDeferredValue } from "react";
|
||||||
import {
|
import {
|
||||||
Search,
|
Search,
|
||||||
Download,
|
Download,
|
||||||
@@ -615,37 +615,35 @@ export function ParcelSyncModule() {
|
|||||||
/* UAT autocomplete filter */
|
/* UAT autocomplete filter */
|
||||||
/* ════════════════════════════════════════════════════════════ */
|
/* ════════════════════════════════════════════════════════════ */
|
||||||
|
|
||||||
|
// useDeferredValue lets React prioritize the input update over the filter
|
||||||
|
const deferredUatQuery = useDeferredValue(uatQuery);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const raw = uatQuery.trim();
|
const raw = deferredUatQuery.trim();
|
||||||
if (raw.length < 2) {
|
if (raw.length < 2) {
|
||||||
setUatResults([]);
|
setUatResults([]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const timer = setTimeout(() => {
|
const isDigit = /^\d+$/.test(raw);
|
||||||
const isDigit = /^\d+$/.test(raw);
|
const query = normalizeText(raw);
|
||||||
const query = normalizeText(raw);
|
const nameMatches: typeof uatData = [];
|
||||||
// Filter and sort: UAT name matches first, then county-only matches
|
const countyOnlyMatches: typeof uatData = [];
|
||||||
const nameMatches: typeof uatData = [];
|
|
||||||
const countyOnlyMatches: typeof uatData = [];
|
|
||||||
|
|
||||||
for (const item of uatData) {
|
for (const item of uatData) {
|
||||||
if (isDigit) {
|
if (isDigit) {
|
||||||
if (item.siruta.startsWith(raw)) nameMatches.push(item);
|
if (item.siruta.startsWith(raw)) nameMatches.push(item);
|
||||||
} else {
|
} else {
|
||||||
const nameMatch = normalizeText(item.name).includes(query);
|
const nameMatch = normalizeText(item.name).includes(query);
|
||||||
const countyMatch =
|
const countyMatch =
|
||||||
item.county && normalizeText(item.county).includes(query);
|
item.county && normalizeText(item.county).includes(query);
|
||||||
if (nameMatch) nameMatches.push(item);
|
if (nameMatch) nameMatches.push(item);
|
||||||
else if (countyMatch) countyOnlyMatches.push(item);
|
else if (countyMatch) countyOnlyMatches.push(item);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UAT name matches first (priority), then county-only matches
|
const results = [...nameMatches, ...countyOnlyMatches].slice(0, 12);
|
||||||
const results = [...nameMatches, ...countyOnlyMatches].slice(0, 12);
|
setUatResults(results);
|
||||||
setUatResults(results);
|
}, [deferredUatQuery, uatData]);
|
||||||
}, 150);
|
|
||||||
return () => clearTimeout(timer);
|
|
||||||
}, [uatQuery, uatData]);
|
|
||||||
|
|
||||||
/* ════════════════════════════════════════════════════════════ */
|
/* ════════════════════════════════════════════════════════════ */
|
||||||
/* Auto-connect: trigger on first UAT keystroke */
|
/* Auto-connect: trigger on first UAT keystroke */
|
||||||
|
|||||||
Reference in New Issue
Block a user