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

开启React Strict Mode后Next.js打字轮播组件字符丢失求助

React Strict Mode下打字组件字符乱码问题解决方案

问题根源

React Strict Mode在开发环境中会重复执行副作用(useEffect)、状态更新函数,如果组件的打字逻辑依赖定时器且未做防重复处理,多个定时器会同时修改状态,导致字符叠加、丢失或乱序。生产环境Strict Mode不会触发两次渲染,但SSR场景下必须保证开发/生产逻辑一致。

核心解决方案

通过useRef控制副作用执行时机、清理定时器,结合函数式状态更新避免闭包陷阱,具体步骤:

  • 用useRef存储定时器ID,每次副作用执行前清理旧定时器
  • 标记首次渲染,跳过Strict Mode下的第二次副作用触发
  • 使用函数式状态更新确保基于最新状态修改文本
  • 用CSS实现光标闪烁,减少定时器依赖

修改后的组件代码

import { useState, useEffect, useRef } from 'react';

const Typewriter = ({ facts }) => {
  const [currentText, setCurrentText] = useState('');
  const [currentIndex, setCurrentIndex] = useState(0);
  const [charIndex, setCharIndex] = useState(0);
  const timerRef = useRef(null);
  const isFirstRender = useRef(true);

  useEffect(() => {
    // Strict Mode下第二次渲染直接跳过副作用
    if (!isFirstRender.current) return;
    isFirstRender.current = false;

    const typeNextChar = () => {
      // 函数式更新确保基于最新state拼接字符
      setCurrentText(prev => prev + facts[currentIndex][charIndex]);
      setCharIndex(prev => prev + 1);
    };

    const switchToNextFact = () => {
      setCurrentIndex(prev => (prev + 1) % facts.length);
      setCharIndex(0);
      setCurrentText('');
    };

    if (charIndex < facts[currentIndex].length) {
      timerRef.current = setTimeout(typeNextChar, 100);
    } else {
      timerRef.current = setTimeout(switchToNextFact, 2000);
    }

    // 清理定时器,防止内存泄漏和重复触发
    return () => timerRef.current && clearTimeout(timerRef.current);
  }, [charIndex, currentIndex, facts]);

  // 组件卸载时重置标记,避免后续重渲染异常
  useEffect(() => {
    return () => isFirstRender.current = true;
  }, []);

  return (
    <div className="typewriter">
      {currentText}
      <span style={{ animation: 'blink 1s infinite', fontWeight: 'bold' }}>|</span>
      <style jsx global>{`
        @keyframes blink {
          0%, 50% { opacity: 1; }
          51%, 100% { opacity: 0; }
        }
      `}</style>
    </div>
  );
};

export default Typewriter;

关键修改说明

  1. 定时器管理:timerRef确保每次只保留一个有效定时器,清理时彻底清除旧定时器,避免多实例同时修改状态
  2. Strict Mode兼容:isFirstRender标记跳过第二次渲染的副作用执行,防止打字逻辑重复触发
  3. 状态更新稳定性:函数式更新避免闭包导致的状态滞后问题,保证字符拼接顺序正确
  4. 光标动画优化:用CSS动画替代定时器控制光标闪烁,减少定时器依赖,避免冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 15:17:50