From bcb5ea1786ab5497552e16bf493be18e41556dab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 08:10:40 +0000 Subject: [PATCH] fix: Use shallow comparison in selector hooks to prevent infinite re-renders The selectors were creating new object references on every call, causing Zustand's subscription system to detect changes and trigger infinite re-render loops. This was particularly evident in usePatternValidationFromStore. Solution: - Import useShallow from zustand/react/shallow - Wrap all selector hooks (usePatternCenter, useUploadedPatternCenter, useRotatedBounds, usePatternValidationFromStore) with useShallow - useShallow performs shallow comparison on returned objects, preventing re-renders when values haven't actually changed This follows the established pattern in the codebase where useShallow is already used extensively (App.tsx, FileUpload.tsx, etc). Co-authored-by: jhbruhn <1036566+jhbruhn@users.noreply.github.com> --- src/stores/usePatternStore.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/stores/usePatternStore.ts b/src/stores/usePatternStore.ts index 5fbe967..d6c26c1 100644 --- a/src/stores/usePatternStore.ts +++ b/src/stores/usePatternStore.ts @@ -1,4 +1,5 @@ import { create } from "zustand"; +import { useShallow } from "zustand/react/shallow"; import type { PesPatternData } from "../formats/import/pesImporter"; import { onPatternDeleted } from "./storeEvents"; import { calculatePatternCenter } from "../components/PatternCanvas/patternCanvasHelpers"; @@ -293,28 +294,33 @@ export const selectPatternValidation = ( }; /** - * Hook to get pattern center (memoized) + * Hook to get pattern center (memoized with shallow comparison) */ -export const usePatternCenter = () => usePatternStore(selectPatternCenter); +export const usePatternCenter = () => + usePatternStore(useShallow(selectPatternCenter)); /** - * Hook to get uploaded pattern center (memoized) + * Hook to get uploaded pattern center (memoized with shallow comparison) */ export const useUploadedPatternCenter = () => - usePatternStore(selectUploadedPatternCenter); + usePatternStore(useShallow(selectUploadedPatternCenter)); /** - * Hook to get rotated bounds (memoized) + * Hook to get rotated bounds (memoized with shallow comparison) */ -export const useRotatedBounds = () => usePatternStore(selectRotatedBounds); +export const useRotatedBounds = () => + usePatternStore(useShallow(selectRotatedBounds)); /** * Hook to get pattern validation result (requires machineInfo) - * Use this with caution as it requires external state + * Uses shallow comparison to prevent infinite re-renders from new object references */ export const usePatternValidationFromStore = ( machineInfo: { maxWidth: number; maxHeight: number } | null, -) => usePatternStore((state) => selectPatternValidation(state, machineInfo)); +) => + usePatternStore( + useShallow((state) => selectPatternValidation(state, machineInfo)), + ); // Subscribe to pattern deleted event. // This subscription is intended to persist for the lifetime of the application,