mirror of
https://github.com/jhbruhn/respira.git
synced 2026-01-27 02:13:41 +00:00
fix: Refactor useCanvasViewport to eliminate ESLint hook warnings
Removed disabled ESLint rules by refactoring state management to follow React best practices. Changes include: - Replaced setState-in-effect pattern with state-during-render pattern for viewport resets - Changed from ref-based to state-based storage for initialScale to avoid ref updates during render - Implemented React-recommended pattern for deriving state from props (similar to getDerivedStateFromProps) - Properly track pattern changes in state to detect when viewport should reset This eliminates the need for ESLint disable comments while maintaining the same functionality. The viewport now correctly resets when patterns change, using a pattern that React explicitly recommends for this use case. Fixes #30 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
7fd31d209c
commit
e8f5c9085c
1 changed files with 35 additions and 44 deletions
|
|
@ -5,13 +5,7 @@
|
||||||
* Handles wheel zoom and button zoom operations
|
* Handles wheel zoom and button zoom operations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { useState, useEffect, useCallback, type RefObject } from "react";
|
||||||
useState,
|
|
||||||
useEffect,
|
|
||||||
useCallback,
|
|
||||||
useRef,
|
|
||||||
type RefObject,
|
|
||||||
} from "react";
|
|
||||||
import type Konva from "konva";
|
import type Konva from "konva";
|
||||||
import type { PesPatternData } from "../formats/import/pesImporter";
|
import type { PesPatternData } from "../formats/import/pesImporter";
|
||||||
import type { MachineInfo } from "../types/machine";
|
import type { MachineInfo } from "../types/machine";
|
||||||
|
|
@ -34,8 +28,11 @@ export function useCanvasViewport({
|
||||||
const [stagePos, setStagePos] = useState({ x: 0, y: 0 });
|
const [stagePos, setStagePos] = useState({ x: 0, y: 0 });
|
||||||
const [stageScale, setStageScale] = useState(1);
|
const [stageScale, setStageScale] = useState(1);
|
||||||
const [containerSize, setContainerSize] = useState({ width: 0, height: 0 });
|
const [containerSize, setContainerSize] = useState({ width: 0, height: 0 });
|
||||||
const initialScaleRef = useRef<number>(1);
|
const [initialScale, setInitialScale] = useState(1);
|
||||||
const prevPesDataRef = useRef<PesPatternData | null>(null);
|
|
||||||
|
// Track the last processed pattern to detect changes during render
|
||||||
|
const [lastProcessedPattern, setLastProcessedPattern] =
|
||||||
|
useState<PesPatternData | null>(null);
|
||||||
|
|
||||||
// Track container size with ResizeObserver
|
// Track container size with ResizeObserver
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -59,19 +56,14 @@ export function useCanvasViewport({
|
||||||
return () => resizeObserver.disconnect();
|
return () => resizeObserver.disconnect();
|
||||||
}, [containerRef]);
|
}, [containerRef]);
|
||||||
|
|
||||||
// Calculate and store initial scale when pattern or hoop changes
|
// Reset viewport when pattern changes (during render, not in effect)
|
||||||
useEffect(() => {
|
// This follows the React-recommended pattern for deriving state from props
|
||||||
// Use whichever pattern is available (uploaded or original)
|
|
||||||
const currentPattern = uploadedPesData || pesData;
|
const currentPattern = uploadedPesData || pesData;
|
||||||
if (!currentPattern || containerSize.width === 0) {
|
if (
|
||||||
prevPesDataRef.current = null;
|
currentPattern &&
|
||||||
return;
|
currentPattern !== lastProcessedPattern &&
|
||||||
}
|
containerSize.width > 0
|
||||||
|
) {
|
||||||
// Only recalculate if pattern changed
|
|
||||||
if (prevPesDataRef.current !== currentPattern) {
|
|
||||||
prevPesDataRef.current = currentPattern;
|
|
||||||
|
|
||||||
const { bounds } = currentPattern;
|
const { bounds } = currentPattern;
|
||||||
const viewWidth = machineInfo
|
const viewWidth = machineInfo
|
||||||
? machineInfo.maxWidth
|
? machineInfo.maxWidth
|
||||||
|
|
@ -80,20 +72,20 @@ export function useCanvasViewport({
|
||||||
? machineInfo.maxHeight
|
? machineInfo.maxHeight
|
||||||
: bounds.maxY - bounds.minY;
|
: bounds.maxY - bounds.minY;
|
||||||
|
|
||||||
const initialScale = calculateInitialScale(
|
const newInitialScale = calculateInitialScale(
|
||||||
containerSize.width,
|
containerSize.width,
|
||||||
containerSize.height,
|
containerSize.height,
|
||||||
viewWidth,
|
viewWidth,
|
||||||
viewHeight,
|
viewHeight,
|
||||||
);
|
);
|
||||||
initialScaleRef.current = initialScale;
|
|
||||||
|
|
||||||
// Reset view when pattern changes
|
// Update state during render when pattern changes
|
||||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
// This is the recommended React pattern for resetting state based on props
|
||||||
setStageScale(initialScale);
|
setLastProcessedPattern(currentPattern);
|
||||||
|
setInitialScale(newInitialScale);
|
||||||
|
setStageScale(newInitialScale);
|
||||||
setStagePos({ x: containerSize.width / 2, y: containerSize.height / 2 });
|
setStagePos({ x: containerSize.width / 2, y: containerSize.height / 2 });
|
||||||
}
|
}
|
||||||
}, [pesData, uploadedPesData, machineInfo, containerSize]);
|
|
||||||
|
|
||||||
// Wheel zoom handler
|
// Wheel zoom handler
|
||||||
const handleWheel = useCallback((e: Konva.KonvaEventObject<WheelEvent>) => {
|
const handleWheel = useCallback((e: Konva.KonvaEventObject<WheelEvent>) => {
|
||||||
|
|
@ -159,10 +151,9 @@ export function useCanvasViewport({
|
||||||
}, [containerSize]);
|
}, [containerSize]);
|
||||||
|
|
||||||
const handleZoomReset = useCallback(() => {
|
const handleZoomReset = useCallback(() => {
|
||||||
const initialScale = initialScaleRef.current;
|
|
||||||
setStageScale(initialScale);
|
setStageScale(initialScale);
|
||||||
setStagePos({ x: containerSize.width / 2, y: containerSize.height / 2 });
|
setStagePos({ x: containerSize.width / 2, y: containerSize.height / 2 });
|
||||||
}, [containerSize]);
|
}, [initialScale, containerSize]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// State
|
// State
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue