React useEffect 跳过第二次渲染问题排查与修复求助
问题原因
你的代码核心问题是useEffect依赖了screenResponse,每次调用setScreenResponse更新状态后,useEffect都会重新执行。而每次重新执行时,只要index.current还没到阈值,就会创建一个新的setInterval,导致多个定时器同时运行:
- 第一个定时器执行
tick,把index从0加到1,更新screenResponse为"L"; - 此时useEffect重新触发,又创建了第二个定时器;
- 两个定时器几乎同时执行下一次
tick,index直接从1跳到2,跳过了字符"o",直接添加"r",所以你看不到"Lo"的状态。
另外,console.log(screenResponse)打印的是旧状态值,因为状态更新是异步的,screenResponse在tick函数里是闭包捕获的旧值,这也会让你误以为中间状态没出现。
修复方案
重构代码,让定时器只初始化一次,同时单独处理skipDialogue的触发逻辑:
import { useState, useEffect, useRef } from 'react'; function App() { const startingLine = `Lorem ipsum.`; const [screenResponse, setScreenResponse] = useState(''); const [skipDialogue, setSkipDialogue] = useState(false); const index = useRef(0); const intervalRef = useRef(null); // 处理打字定时器 useEffect(() => { // 跳过对话时直接显示完整文本并清除定时器 if (skipDialogue) { setScreenResponse(startingLine); if (intervalRef.current) { clearInterval(intervalRef.current); } return; } // 初始化定时器,只执行一次 intervalRef.current = setInterval(() => { if (index.current < startingLine.length) { setScreenResponse(prev => prev + startingLine[index.current]); index.current++; } else { clearInterval(intervalRef.current); } }, 500); // 组件卸载时清除定时器 return () => clearInterval(intervalRef.current); }, [skipDialogue, startingLine]); // 重置逻辑(如果需要重新触发打字效果) const resetDialogue = () => { setScreenResponse(''); index.current = 0; setSkipDialogue(false); }; return ( <div> <p>{screenResponse}</p> <button onClick={() => setSkipDialogue(true)}>跳过对话</button> <button onClick={resetDialogue}>重新播放</button> </div> ); } export default App;
关键优化点
- 去掉
screenResponse作为useEffect的依赖,改用空依赖数组配合useRef保存定时器引用,确保只创建一个定时器; - 用
intervalRef保存定时器ID,方便在跳过对话或组件卸载时清除; - 直接判断
index.current < startingLine.length即可,不需要减1——因为当index等于字符串长度时,循环停止,不会出现undefined; - 单独监听
skipDialogue状态,触发时直接设置完整文本并清除定时器。
额外说明
之前的console.log(screenResponse)无法正确打印实时状态,因为状态更新是异步的,闭包会捕获旧的状态值。如果需要调试,可以在setScreenResponse的回调里打印,或者用useEffect监听screenResponse的变化:
useEffect(() => { console.log('当前显示:', screenResponse); }, [screenResponse]);
内容的提问来源于stack exchange,提问作者theLoganaut
相关产品推荐
相关产品推荐

