React中useEffect结合setTimeout为何重复添加字符?
React字符串逐字符重复添加问题解决方法
问题根源是React 18开发环境下的Strict Mode——它会自动执行两次带有空依赖数组的useEffect,你的定时器逻辑被触发了两次,所以每个字符会被添加两遍。
下面给两种可行的解决办法:
方法一:清理定时器
在useEffect的返回函数中清除所有定时器,避免重复执行的逻辑继续运行:
const [placeholder, setPlaceholder] = useState<string>(''); useEffect(() => { const str = "How may I help you today?"; const letters = Array.from(str); const timerIds: number[] = []; const addLetterWithDelay = (index: number) => { if (index < letters.length) { const timerId = setTimeout(() => { setPlaceholder(prev => prev + letters[index]); addLetterWithDelay(index + 1); }, 1000); timerIds.push(timerId); } }; addLetterWithDelay(0); // 组件卸载或重新执行useEffect时清除所有定时器 return () => { timerIds.forEach(id => clearTimeout(id)); }; }, []);
方法二:用Ref标记初始化状态
通过一个ref变量判断是否已经启动过定时器,避免重复触发:
const [placeholder, setPlaceholder] = useState<string>(''); const hasInitiated = useRef(false); useEffect(() => { // 如果已经启动过,直接返回 if (hasInitiated.current) return; hasInitiated.current = true; const str = "How may I help you today?"; const letters = Array.from(str); const addLetterWithDelay = (index: number) => { if (index < letters.length) { setTimeout(() => { setPlaceholder(prev => prev + letters[index]); addLetterWithDelay(index + 1); }, 1000); } }; addLetterWithDelay(0); }, []);
注意:生产环境下Strict Mode不会触发两次执行,所以上面的方法主要是解决开发环境的重复问题。
内容的提问来源于stack exchange,提问作者Adam Basha
相关产品推荐
相关产品推荐

