From 49daf68830b73f434610ab6c32c0e9d30f412ffb Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 10 Feb 2026 03:16:46 +0000 Subject: [PATCH] fix: resolve setState-in-effect and missing deps lint errors in editor MapPreviewModal: Replace useEffect that clamped numPlayers with a derived value using Math.min, eliminating the synchronous setState inside an effect that caused cascading renders. SettingsPanel: Use refs synced via useEffect for state.mapData and onUpdateObjects in the border decoration auto-regeneration effect, fixing the exhaustive-deps warning without causing unwanted effect triggers on parent re-renders. https://claude.ai/code/session_01B6rVfPyBb24TYHZhFshRvZ --- src/editor/core/MapPreviewModal.tsx | 18 ++-- src/editor/core/panels/SettingsPanel.tsx | 101 +++++++++++++++++------ 2 files changed, 82 insertions(+), 37 deletions(-) diff --git a/src/editor/core/MapPreviewModal.tsx b/src/editor/core/MapPreviewModal.tsx index 0c697ea4..f8bad031 100644 --- a/src/editor/core/MapPreviewModal.tsx +++ b/src/editor/core/MapPreviewModal.tsx @@ -23,14 +23,8 @@ export function MapPreviewModal({ maxPlayers, onLaunch, onCancel }: MapPreviewMo const [gameSpeed, setGameSpeed] = useState('normal'); const [fogOfWar, setFogOfWar] = useState(false); const [aiDifficulty, setAiDifficulty] = useState('medium'); - const [numPlayers, setNumPlayers] = useState(2); - - // Clamp player count if maxPlayers changes - useEffect(() => { - if (numPlayers > maxPlayers) { - setNumPlayers(maxPlayers); - } - }, [maxPlayers, numPlayers]); + const [numPlayersRaw, setNumPlayers] = useState(2); + const numPlayers = Math.min(numPlayersRaw, maxPlayers); const handleLaunch = useCallback(() => { onLaunch({ startingResources, gameSpeed, fogOfWar, aiDifficulty, numPlayers }); @@ -54,10 +48,7 @@ export function MapPreviewModal({ maxPlayers, onLaunch, onCancel }: MapPreviewMo return (
{/* Backdrop */} -
+
{/* Modal */}
@@ -120,7 +111,8 @@ export function MapPreviewModal({ maxPlayers, onLaunch, onCancel }: MapPreviewMo className={`w-10 h-5 rounded-full transition-all duration-200 relative ${fogOfWar ? 'bg-void-500' : 'bg-void-800'}`} > -
diff --git a/src/editor/core/panels/SettingsPanel.tsx b/src/editor/core/panels/SettingsPanel.tsx index 396d6896..0d1efbab 100644 --- a/src/editor/core/panels/SettingsPanel.tsx +++ b/src/editor/core/panels/SettingsPanel.tsx @@ -1,7 +1,12 @@ 'use client'; import { useState, useEffect, useRef } from 'react'; -import type { EditorConfig, EditorState, EditorMapData, EditorObject } from '../../config/EditorConfig'; +import type { + EditorConfig, + EditorState, + EditorMapData, + EditorObject, +} from '../../config/EditorConfig'; import { Section, ToggleSwitch } from './shared'; import { generateBorderDecorations, @@ -17,7 +22,9 @@ export interface SettingsPanelProps { state: EditorState; visibility: { labels: boolean; grid: boolean; categories: Record }; onBiomeChange: (biomeId: string) => void; - onMetadataUpdate: (updates: Partial>) => void; + onMetadataUpdate: ( + updates: Partial> + ) => void; onToggleLabels: () => void; onToggleGrid: () => void; onToggleCategory: (category: string) => void; @@ -43,6 +50,16 @@ export function SettingsPanel({ const [borderScale, setBorderScale] = useState(2.0); // Average of scaleMin/scaleMax const [isGenerating, setIsGenerating] = useState(false); const isInitialMount = useRef(true); + const stateRef = useRef(state); + const onUpdateObjectsRef = useRef(onUpdateObjects); + + useEffect(() => { + stateRef.current = state; + }, [state]); + + useEffect(() => { + onUpdateObjectsRef.current = onUpdateObjects; + }, [onUpdateObjects]); // Auto-regenerate border decorations when style, density, or scale changes (if decorations exist) useEffect(() => { @@ -53,8 +70,10 @@ export function SettingsPanel({ } // Only auto-regenerate if there are existing border decorations - if (!state.mapData || !onUpdateObjects) return; - const currentCount = countBorderDecorations(state.mapData.objects); + const mapData = stateRef.current.mapData; + const updateObjects = onUpdateObjectsRef.current; + if (!mapData || !updateObjects) return; + const currentCount = countBorderDecorations(mapData.objects); if (currentCount === 0) return; // Regenerate with new settings @@ -66,8 +85,8 @@ export function SettingsPanel({ scaleMax: borderScale * 1.4, }; - const newObjects = generateBorderDecorations(state.mapData, settings); - onUpdateObjects(newObjects); + const newObjects = generateBorderDecorations(mapData, settings); + updateObjects(newObjects); }, [borderStyle, borderDensity, borderScale]); if (!state.mapData) return null; @@ -104,7 +123,10 @@ export function SettingsPanel({
-