You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

useEffect内打字机效果异常:代码跳过文本索引1的问题排查

打字机效果实现中的字符跳过问题分析

在实现React打字机效果时,你遇到了第一种写法跳过"hello world"索引1字符(最终显示"hllo world"),但第二种写法正常的情况,下面具体分析原因:

问题代码回顾

第一种有问题的写法:

export default function App() {
  const [message, setMessage] = useState("");
  const index = useRef(0);
  const text = "hello world";

  useEffect(() => {
    const interval = setInterval(() => {
      setMessage((prevMessage) => prevMessage + text[index.current]);
      index.current++;
    }, 500);

    return () => clearInterval(interval);
  }, []);

  return (
    <div className="App">
      <h1>{message}</h1>
    </div>
  );
}

修正后的写法(替换setMessage部分):

setMessage(text.substring(0, index.current));

核心差异分析

第一种写法的问题

这种写法依赖上一次的message状态和index.current同步累加字符:每次从text中取当前index对应的字符,拼接到之前的message后面,再让index自增。

它的风险在于:一旦message的状态更新和index.current的递增不同步,就会导致字符丢失。比如:

  • 若遇到React严格模式(开发环境下会重复执行挂载/卸载逻辑),或意外创建了多个定时器,index.current可能被多次递增,但message的状态更新没跟上(比如上一次的状态更新还未完成),就会出现message长度和index.current不匹配的情况。
  • 举个实际场景:假设index.current直接从1跳到2,此时message还是"h",拼接text[2](即"l")后就会变成"hl",直接跳过了"e"。

第二种写法的优势

这种写法完全不依赖之前的message状态,而是直接从原始文本text中截取前index.current个字符。

不管index.current是如何变化的(哪怕出现异常递增),它都会直接从源文本中取对应长度的片段,保证显示的内容和index.current完全匹配。比如:

  • 当index.current是2时,不管之前的message是什么,都会截取text的前2个字符"he",从根源上避免了状态不同步导致的字符丢失问题。

内容的提问来源于stack exchange,提问作者valbert_martins

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 11:55:40