Quellcode durchsuchen

fix: replace fragile ref pattern with reliable state-driven auto-trigger in Steps 0/1/2

nonvioce vor 6 Monaten
Ursprung
Commit
055d00fd6d

+ 9 - 11
src/app/features/novel-writer/components/pipeline/Step0ControlCard.tsx

@@ -1,6 +1,6 @@
 'use client';
 
-import { useState, useEffect, useRef } from 'react';
+import { useState, useEffect } from 'react';
 import { Sparkles, ArrowRight, ChevronDown, ChevronUp } from 'lucide-react';
 import type { EventNode } from '@/app/lib/novel-types';
 
@@ -65,17 +65,17 @@ export default function Step0ControlCard({
   const [chapterPlans, setChapterPlans] = useState<ChapterPlan[]>([]);
   const [selectedPlanIndex, setSelectedPlanIndex] = useState<number | null>(null);
   const [expandedPlanIndex, setExpandedPlanIndex] = useState<number | null>(null);
-  const autoModeStartedRef = useRef(false);
-  const handleGenerateRef = useRef<() => void>(() => {});
+  const [autoGenerate, setAutoGenerate] = useState(false);
 
-  // Auto-mode: auto-trigger generation on mount
   useEffect(() => {
-    if (autoMode && apiSettings && !autoModeStartedRef.current) {
-      autoModeStartedRef.current = true;
-      const timer = setTimeout(() => handleGenerateRef.current(), 300);
-      return () => clearTimeout(timer);
+    if (autoMode && apiSettings && !autoGenerate) {
+      setAutoGenerate(true);
     }
-  }, [autoMode, apiSettings]);
+  }, [autoMode, apiSettings, autoGenerate]);
+
+  useEffect(() => {
+    if (autoGenerate) handleGenerate();
+  }, [autoGenerate]);
 
   const handleGenerate = async () => {
     if (!apiSettings) return;
@@ -252,8 +252,6 @@ ${projectContext || '(项目文档不可用)'}
     });
   };
 
-  // Keep ref in sync for auto-mode trigger
-  handleGenerateRef.current = handleGenerate;
 
   return (
     <div className="flex-1 overflow-y-auto">

+ 9 - 11
src/app/features/novel-writer/components/pipeline/Step2EmbedHooks.tsx

@@ -1,6 +1,6 @@
 'use client';
 
-import { useState, useCallback, useEffect, useRef } from 'react';
+import { useState, useCallback, useEffect } from 'react';
 import { RefreshCw, ChevronRight, ChevronLeft, Plus, Loader2, AlertCircle, CheckSquare, Square } from 'lucide-react';
 
 interface ApiSettings {
@@ -42,17 +42,17 @@ export default function Step2EmbedHooks({
   const [manualHook, setManualHook] = useState('');
   const [manualHooks, setManualHooks] = useState<string[]>(savedManualHooks);
   const [tokenUsage, setTokenUsage] = useState<string | null>(null);
-  const autoModeStartedRef = useRef(false);
-  const generateHooksRef = useRef<() => Promise<void>>(async () => {});
+  const [autoGenerate, setAutoGenerate] = useState(false);
 
-  // Auto-mode: auto-trigger generation on mount
   useEffect(() => {
-    if (autoMode && apiSettings && !autoModeStartedRef.current) {
-      autoModeStartedRef.current = true;
-      const timer = setTimeout(() => generateHooksRef.current(), 300);
-      return () => clearTimeout(timer);
+    if (autoMode && apiSettings && !autoGenerate) {
+      setAutoGenerate(true);
     }
-  }, [autoMode, apiSettings]);
+  }, [autoMode, apiSettings, autoGenerate]);
+
+  useEffect(() => {
+    if (autoGenerate) generateHookOptions();
+  }, [autoGenerate]);
 
   // Auto-mode: auto-advance after hooks are generated
   useEffect(() => {
@@ -129,8 +129,6 @@ ${chapterPlanSummary}
     }
   }, [apiSettings, chapterPlanSummary]);
 
-  generateHooksRef.current = generateHookOptions;
-
   const toggleHook = (id: string) => {
     setSelectedHookIds((prev) => {
       const next = new Set(prev);

+ 8 - 9
src/app/features/novel-writer/components/pipeline/Step4ContentEditor.tsx

@@ -674,19 +674,18 @@ ${antiText}
   }, [projectPath]);
 
   // Auto-mode: auto-trigger generation on mount
-  const autoContentStartedRef = useRef(false);
   const autoDeAIStartedRef = useRef(false);
-  const generateContentRef = useRef<() => Promise<void>>(async () => {});
-
-  generateContentRef.current = generateContent;
+  const [autoGenerate, setAutoGenerate] = useState(false);
 
   useEffect(() => {
-    if (autoMode && apiSettings && !autoContentStartedRef.current && !isGenerating) {
-      autoContentStartedRef.current = true;
-      const timer = setTimeout(() => generateContentRef.current(), 300);
-      return () => clearTimeout(timer);
+    if (autoMode && apiSettings && !autoGenerate && !isGenerating) {
+      setAutoGenerate(true);
     }
-  }, [autoMode, apiSettings, isGenerating]);
+  }, [autoMode, apiSettings, autoGenerate, isGenerating]);
+
+  useEffect(() => {
+    if (autoGenerate) generateContent();
+  }, [autoGenerate]);
 
   // Auto-mode: auto-run de-AI after generation, then auto-advance
   useEffect(() => {