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
相关产品推荐
相关产品推荐

