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:
@@ -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("");
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user