React中3个容器的顺序打字效果实现需求及优化问询
React 实现逐容器顺序打字效果的简洁方案
需求说明
需要实现三个并排容器的打字效果:从最左侧容器开始,完成该容器的字符串打字后,再依次启动后续容器,最终每行展示time、message、eventid三个字段,按顺序完成每行的打字后再处理下一行。
简洁实现方案
核心思路
- 用二维数组
typingProgress记录每一行每个字段的已输入字符长度 - 按「行→字段」的顺序逐字符打字,完成一个字段后切换到下一个字段,完成一行后切换到下一行
- 定时器自动处理打字进度,完成所有内容后自动终止
完整代码实现
import { useState, useEffect } from 'react'; import classes from './YourComponent.module.css'; // 替换为你的样式文件 const TypingLog = ({ log }) => { // typingProgress:二维数组,[行索引][字段索引] → 已输入字符长度 // 字段索引:0=time,1=message,2=eventid const [typingProgress, setTypingProgress] = useState([]); const [currentRow, setCurrentRow] = useState(0); // 当前正在打字的行 const [currentField, setCurrentField] = useState(0); // 当前正在打字的字段 useEffect(() => { if (!log || log.length === 0) return; // 初始化进度数组:每一行的三个字段初始长度都是0 if (typingProgress.length === 0) { setTypingProgress(log.map(() => [0, 0, 0])); } const interval = setInterval(() => { setTypingProgress(prev => { const newProgress = [...prev]; const fieldNames = ['time', 'message', 'eventid']; const targetField = fieldNames[currentField]; const targetText = log[currentRow][targetField]; const currentLength = newProgress[currentRow][currentField]; // 1. 当前字段未打完:增加长度 if (currentLength < targetText.length) { newProgress[currentRow][currentField] += 1; return newProgress; } // 2. 当前字段打完,切换到同一下一行的下一个字段 else if (currentField < 2) { setCurrentField(prevField => prevField + 1); return newProgress; } // 3. 当前行所有字段打完,切换到下一行的第一个字段 else if (currentRow < log.length - 1) { setCurrentRow(prevRow => prevRow + 1); setCurrentField(0); return newProgress; } // 4. 所有内容打完:清除定时器 else { clearInterval(interval); return newProgress; } }); }, 1000); // 打字速度:每秒1个字符,可自行调整 return () => clearInterval(interval); }, [log, typingProgress, currentRow, currentField]); return ( <div className={classes.logContainer}> {log.map((item, rowIdx) => ( <div key={rowIdx} className={classes.row}> <span className={classes.time}> {item.time.slice(0, typingProgress[rowIdx]?.[0] || 0)} </span> <span className={classes.message}> {item.message.slice(0, typingProgress[rowIdx]?.[1] || 0)} </span> <span className={classes.event}> {item.eventid.slice(0, typingProgress[rowIdx]?.[2] || 0)} </span> </div> ))} </div> ); }; export default TypingLog;
方案优势
- 逻辑清晰:按固定顺序处理,每一步只关注当前要打字的内容,无需复杂的数组操作
- 状态简洁:用二维数组直接记录进度,避免原方案中混乱的数组拼接逻辑
- 自动终止:所有内容完成后自动清除定时器,避免内存泄漏
- 易于扩展:修改打字速度、调整字段顺序或新增字段都只需少量改动
原问题代码(无法正常运行)
const [text, setText] = useState([]); const [currentIndex, setCurrentIndex] = useState(0); const [currentText, setCurrentText] = useState([]); // Setting Text Content For Typing useEffect(() => { if(log && log.length > 0 && text.length == 0){ log.map((item, key) => { let time = item['time']; let message = item['message']; let event = item['eventid']; setText((prev) => [...prev, time, message, event]); }); } }, [log, text]); useEffect(() => { if(currentText?.length < text?.length){ const interval = setInterval(()=> { // Setting Current index if(currentText?.length !== 0 && currentIndex !== currentText?.length -1) { setCurrentIndex(currentText?.length -1); } // Check if the last index string completed if(currentText[currentIndex]?.length !== text[currentIndex]?.length){ let temp = currentText; let lastText = temp[currentIndex]; if(lastText) lastText = lastText + text[currentIndex].charAt(lastText?.length -1); else lastText = text[currentIndex].charAt(0); temp[currentIndex] = lastText; setCurrentText(temp); } // If completed open new array element to contain new string else{ setCurrentText((prev) => [...prev, ['']]); } }, 1000); return () => clearInterval(interval); } }, [currentText, text, currentIndex]); return ( <> { currentText && currentText.length > 0 && currentText.map((item, key) => { <div key={key} className={classes.row}> <span className={classes.time}>{currentText[key]}</span> <span className={classes.message}>{key % 1 ? currentText[key] : currentText[key+1]}</span> <span className={classes.event}>{key % 2 ? currentText[key] : currentText[key+2]}</span> </div> }) } </> );
原数据示例
[ {time: '2023-02-19 06:25:30', message: 'some message', eventid: 'event_string'}, {time: '2023-02-19 06:25:30', message: 'some message', eventid: 'event_string'}, {time: '2023-02-19 06:25:30', message: 'some message', eventid: 'event_string'}, ]
内容的提问来源于stack exchange,提问作者David Sachakov
相关产品推荐
相关产品推荐

