fix: react-doctor rerender-state-only-in-handlers 37→5 (ref for handler-only state in QRScanModal, HeroSection, MessageLogPanel, FsmaReportModal, SettingsSections, TimeTrackingSettingsClient, OrderEditForm, ProductFormModal, ProductsClient, CampaignComposerPage, MatchingCustomersPanel, SegmentBuilderPanel, MessageCustomersSection, ShippingSettingsForm, StopEditForm, StopTableClient, TimeTrackingFieldClient, WaterFieldClient, UsersPage, LotCreateModal, LotDetailPanel, WholesaleClient, ContactImportForm, AdminOrdersPanel, TuxedoPage)

This commit is contained in:
Nora
2026-06-26 07:10:42 -06:00
parent ce2dc8f070
commit ad0a0fe4ec
20 changed files with 161 additions and 181 deletions
@@ -62,7 +62,7 @@ function MatchingCustomersBody({ brandId, rules, onCountChange }: Props) {
const [loading, setLoading] = useState(rules.filters.length > 0);
const [search, setSearch] = useState("");
const [page, setPage] = useState(0);
const [customerCount, setCustomerCount] = useState<number | undefined>(undefined);
const customerCountRef = useRef<number | undefined>(undefined);
const timerRef = useRef<ReturnType<typeof setTimeout>>(undefined);
// useEffectEvent so we always call the latest onCountChange without
@@ -76,7 +76,7 @@ function MatchingCustomersBody({ brandId, rules, onCountChange }: Props) {
// `rules.filters.length === 0` is intentionally a no-op here: when
// the outer panel remounts this body via `key={syncKey}` (which
// encodes rules), the initial useState values already give us
// `preview = null` and `customerCount = undefined`. Adjusting
// `preview = null` and `customerCountRef.current = undefined`. Adjusting
// them again inside this effect would be the anti-pattern the
// `no-adjust-state-on-prop-change` rule warns about — it forces
// an extra render with a stale UI between the two commits.
@@ -87,7 +87,7 @@ function MatchingCustomersBody({ brandId, rules, onCountChange }: Props) {
setPreview(result);
setLoading(false);
const count = result?.count ?? 0;
setCustomerCount(count);
customerCountRef.current = count;
onCountChangeEffect(count);
}, DEBOUNCE_MS);
return () => clearTimeout(timerRef.current);