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
@@ -181,9 +181,8 @@ export default function FsmaReportModal({ brandId }: { brandId: string }) {
// Track the most recent fetch signature so the effect below can
// request fresh data when the user changes the date range or hits
// the refresh button.
const [refreshTick, setRefreshTick] = useState(0);
const fetchSignature = open && startDate && endDate && brandId
? `${brandId}|${startDate}|${endDate}|${refreshTick}`
? `${brandId}|${startDate}|${endDate}`
: null;
// Kicks off a fetch and writes the result into state. Stable enough
@@ -226,7 +225,10 @@ export default function FsmaReportModal({ brandId }: { brandId: string }) {
}, [fetchSignature, performFetch]);
function fetchComplianceData() {
setRefreshTick((n) => n + 1);
// Inline the same logic as the effect above — performFetch with a
// fresh cancellation signal.
const signal = { cancelled: false };
void performFetch(signal);
}
function handleDownload() {
@@ -1,6 +1,6 @@
"use client";
import { useState, useTransition } from "react";
import { useState, useTransition, useRef } from "react";
import { useRouter } from "next/navigation";
import { createHarvestLot } from "@/actions/route-trace/lots";
@@ -33,12 +33,10 @@ export default function LotCreateModal({ isOpen, onClose, brandId }: Props) {
const [notes, setNotes] = useState("");
// Track the previous isOpen value to detect a transition from closed → open,
// which is when we want to reset the form. The initial value is a literal
// (not derived from a prop) so a stale useState copy can't occur if the
// parent passes a new isOpen value.
const [prevIsOpen, setPrevIsOpen] = useState(false);
if (isOpen !== prevIsOpen) {
setPrevIsOpen(isOpen);
// which is when we want to reset the form.
const prevIsOpenRef = useRef(false);
if (isOpen !== prevIsOpenRef.current) {
prevIsOpenRef.current = isOpen;
if (isOpen) {
setCropType("");
setVariety("");
+5 -5
View File
@@ -62,7 +62,7 @@ export default function QRScanModal({ onClose, onScanResult }: QRScanModalProps)
const [manualInput, setManualInput] = useState("");
const [cameraError, setCameraError] = useState<string | null>(null);
const [cameraStarting, setCameraStarting] = useState(true);
const [detected, setDetected] = useState(false);
const detectedRef = useRef(false);
const [scanSuccess, setScanSuccess] = useState(false);
const videoRef = useRef<HTMLVideoElement>(null);
const streamRef = useRef<MediaStream | null>(null);
@@ -147,15 +147,15 @@ export default function QRScanModal({ onClose, onScanResult }: QRScanModalProps)
// Scan loop
const scan = async () => {
if (!mounted || detected || !detectorRef.current || !videoRef.current) return;
if (!mounted || detectedRef.current || !detectorRef.current || !videoRef.current) return;
if (videoRef.current.readyState < 2) {
scanRef.current = requestAnimationFrame(scan);
return;
}
try {
const barcodes = await detectorRef.current.detect(videoRef.current);
if (barcodes.length > 0 && !detected) {
setDetected(true);
if (barcodes.length > 0 && !detectedRef.current) {
detectedRef.current = true;
setScanSuccess(true);
const raw = barcodes[0].rawValue;
if (streamRef.current) streamRef.current.getTracks().forEach(t => t.stop());
@@ -184,7 +184,7 @@ export default function QRScanModal({ onClose, onScanResult }: QRScanModalProps)
if (scanRef.current) cancelAnimationFrame(scanRef.current);
if (streamRef.current) streamRef.current.getTracks().forEach((t) => t.stop());
};
}, [mode, detected]);
}, [mode]);
function handleManualSubmit(e: React.FormEvent) {
e.preventDefault();