From fe5bb300826608a2add7350bcdc94761b503ff2a Mon Sep 17 00:00:00 2001 From: Victor Garcia Date: Thu, 18 Jun 2026 01:16:18 -0600 Subject: [PATCH] fix(react): stop calling Date.now()/new Date() during render Two real render-purity bugs: EstimatePdf computed the estimate # from Date.now() during render (so it changed on every re-render) and the date likewise; ExpirationAlerts read Date.now() in render. Both now stamp once at mount (useMemo / lazy useState). Also clears a dead eslint-disable in ErrorBoundary and a // comment-textnode in EstimateResults. Lint warnings 22 -> 18 (the rest are the localStorage-hydration set-state-in-effect pattern, left for a deliberate burndown). Co-Authored-By: Claude Opus 4.8 (1M context) --- components/estimator/estimate-pdf.tsx | 22 +++++++++++++++------- components/estimator/estimate-results.tsx | 2 +- components/ui/error-boundary.tsx | 1 - components/vault/expiration-alerts.tsx | 4 +++- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/components/estimator/estimate-pdf.tsx b/components/estimator/estimate-pdf.tsx index 024275a..f4831c9 100644 --- a/components/estimator/estimate-pdf.tsx +++ b/components/estimator/estimate-pdf.tsx @@ -2,6 +2,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // Copyright (C) 2026 Steel-Tech / StructuPath +import { useMemo } from "react"; import { Printer } from "lucide-react"; import { formatCurrency, formatCurrencyPrecise } from "@/lib/estimator/calculate"; import type { EstimateInput, EstimateResult } from "@/lib/types/estimator"; @@ -18,11 +19,19 @@ export function EstimatePdf({ result, companyName = "IronForge Estimator", }: Props) { - const today = new Date().toLocaleDateString("en-US", { - year: "numeric", - month: "long", - day: "numeric", - }); + // Stamp the date + estimate id once at mount — computing them during render + // is impure (the id would change on every re-render). + const { today, estimateId } = useMemo(() => { + const now = new Date(); + return { + today: now.toLocaleDateString("en-US", { + year: "numeric", + month: "long", + day: "numeric", + }), + estimateId: now.getTime().toString().slice(-6), + }; + }, []); const stateData = input.state ? STATE_REGISTRY[input.state] : undefined; function handlePrint() { @@ -52,8 +61,7 @@ export function EstimatePdf({ Date: {today}
- Estimate #: EST- - {Date.now().toString().slice(-6)} + Estimate #: EST-{estimateId}
diff --git a/components/estimator/estimate-results.tsx b/components/estimator/estimate-results.tsx index 41a1e15..324069f 100644 --- a/components/estimator/estimate-results.tsx +++ b/components/estimator/estimate-results.tsx @@ -34,7 +34,7 @@ export function EstimateResults({ input, result }: Props) {
- // Total Bid Estimate + {"// Total Bid Estimate"}
diff --git a/components/ui/error-boundary.tsx b/components/ui/error-boundary.tsx index 104ae18..91c39b7 100644 --- a/components/ui/error-boundary.tsx +++ b/components/ui/error-boundary.tsx @@ -32,7 +32,6 @@ export class ErrorBoundary extends Component Date.now()); const thirty = 30 * 86_400_000; const seven = 7 * 86_400_000;