Ver Fonte

🐛fix: Fix React hooks order violation causing page crash on API errors

- Move useEffect hooks before conditional returns in MessageContent and ThinkingContent
- Ensure hooks are called in the same order every render
- Fix "Rendered fewer hooks than expected" error when API returns non-200 status
- Follow React hooks rules: only call hooks at the top level

This prevents the entire page from crashing when API requests fail.
Apple\Apple há 9 meses atrás
pai
commit
f9c8a802ef

+ 9 - 9
web/src/components/playground/MessageContent.js

@@ -28,6 +28,15 @@ const MessageContent = ({
   const previousContentLengthRef = useRef(0);
   const lastContentRef = useRef('');
 
+  const isThinkingStatus = message.status === 'loading' || message.status === 'incomplete';
+
+  useEffect(() => {
+    if (!isThinkingStatus) {
+      previousContentLengthRef.current = 0;
+      lastContentRef.current = '';
+    }
+  }, [isThinkingStatus]);
+
   if (message.status === 'error') {
     let errorText;
 
@@ -51,7 +60,6 @@ const MessageContent = ({
     );
   }
 
-  const isThinkingStatus = message.status === 'loading' || message.status === 'incomplete';
   let currentExtractedThinkingContent = null;
   let currentDisplayableFinalContent = "";
   let thinkingSource = null;
@@ -130,14 +138,6 @@ const MessageContent = ({
   const finalExtractedThinkingContent = currentExtractedThinkingContent;
   const finalDisplayableFinalContent = currentDisplayableFinalContent;
 
-  // 流式状态结束时重置
-  useEffect(() => {
-    if (!isThinkingStatus) {
-      previousContentLengthRef.current = 0;
-      lastContentRef.current = '';
-    }
-  }, [isThinkingStatus]);
-
   if (message.role === 'assistant' &&
     isThinkingStatus &&
     !finalExtractedThinkingContent &&

+ 3 - 6
web/src/components/playground/ThinkingContent.js

@@ -15,25 +15,23 @@ const ThinkingContent = ({
   const scrollRef = useRef(null);
   const lastContentRef = useRef('');
 
-  if (!finalExtractedThinkingContent) return null;
-
   const isThinkingStatus = message.status === 'loading' || message.status === 'incomplete';
   const headerText = (isThinkingStatus && !message.isThinkingComplete) ? t('思考中...') : t('思考过程');
 
   useEffect(() => {
-    if (scrollRef.current) {
+    if (scrollRef.current && finalExtractedThinkingContent && message.isReasoningExpanded) {
       scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
     }
   }, [finalExtractedThinkingContent, message.isReasoningExpanded]);
 
-  // 流式状态结束时重置
   useEffect(() => {
     if (!isThinkingStatus) {
       lastContentRef.current = '';
     }
   }, [isThinkingStatus]);
 
-  // 获取上一次的内容长度
+  if (!finalExtractedThinkingContent) return null;
+
   let prevLength = 0;
   if (isThinkingStatus && lastContentRef.current) {
     if (finalExtractedThinkingContent.startsWith(lastContentRef.current)) {
@@ -41,7 +39,6 @@ const ThinkingContent = ({
     }
   }
 
-  // 更新最后内容的引用
   if (isThinkingStatus) {
     lastContentRef.current = finalExtractedThinkingContent;
   }