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

React渲染异常:动态更新数组后旧UI内容消失问题求助

Next.js 13.2 App目录打字动画渲染异常修复

问题现象

在Next.js 13.2的App目录开发CEO友好型打字动画组件时,出现渲染异常:

  • 静态赋值数组strArr并通过<p>{strArr[0] + strArr[1]} <span>{strArr[2]}</span></p>渲染时,显示完全正常
  • 分阶段依次为strArr[0]、strArr[1]、strArr[2]赋值后,{strArr[0]+strArr[1]}的内容停止渲染,仅strArr[2]能正常显示

问题原因

核心问题是闭包捕获旧状态:

  • useEffect的依赖数组为空,导致其内部回调函数捕获的是组件初始化时的displayedText状态(全为空字符串)
  • 进入第二个阶段(填充strArr[1])时,代码中直接使用的displayedText[0]始终是初始空值,因此displayedText[0]+displayedText[1]拼接后为空
  • 第三个阶段同理,displayedText[0]和displayedText[1]都保持初始空状态,最终只有strArr[2]的内容能正常渲染

修复方法

使用React状态更新的函数式形式,让每次状态更新都基于最新的状态值,避免闭包捕获旧状态的问题:

  • 将setDisplayedText的参数从直接赋值改为接收prevState(最新状态)的回调函数
  • 在回调中基于prevState进行状态更新,确保每次用到的都是最新的状态值

修复后完整代码

"use client";
import Link from "next/link";
import { useEffect, useState } from "react";

type Props = {};

export default function TypeIn({}: Props) {
  // 动画总时长(毫秒)
  const aniLength = 2000;
  const text: [string, string, string] = [
    "Hello, my name is",
    " ",
    "Dennis Lonoshchuk",
  ];
  const fullText = text[0] + text[1] + text[2];
  const [displayedText, setDisplayedText] = useState<[string, string, string]>([
    "",
    "",
    "",
  ]);

  useEffect(() => {
    const iterAmount = fullText.length;
    const nextIter = aniLength / fullText.length;
    let i = 1;
    const interval = setInterval(() => {
      setDisplayedText((prevState) => {
        if (i <= text[0].length) {
          return [fullText.slice(0, i), "", ""];
        } else if (i <= text[0].length + text[1].length) {
          return [
            prevState[0],
            fullText.slice(text[0].length, i),
            "",
          ];
        } else if (i <= iterAmount) {
          return [
            prevState[0],
            prevState[1],
            fullText.slice(text[0].length + text[1].length, i),
          ];
        }
        return prevState;
      });

      if (i >= iterAmount) {
        clearInterval(interval);
      } else {
        i++;
      }
    }, nextIter);

    // 组件卸载时清理定时器,避免内存泄漏
    return () => clearInterval(interval);
  }, []);

  return (
    <>
      <h1 className="hidden">{fullText}</h1>
      <p
        className={`font-semibold text-4xl sm:text-6xl md:text-7xl
text-stroke-2 pt-[max(76px,32vh)]`}
      >
        {displayedText[0] + displayedText[1]}
        <Link
          href="/contact"
          className="text-transparent dark:text-stroke-white text-stroke-black text-stroke-2
dark:hover:text-white hover:text-black
transition-all ease-in-out duration-300"
        >
          {displayedText[2]}
        </Link>
      </p>
    </>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 22:32:52