React中useEffect与componentDidUpdate对比使用及功能实现问题
解决方案
核心问题定位
你出现无限循环的直接原因是把状态lines放到了useEffect的依赖数组中:当你在useEffect内部调用setLines修改lines的值时,会触发依赖项变化,进而重新执行useEffect、再次调用setLines,形成无限死循环。
另外你当前的依赖设置也不符合业务逻辑:触发SVG文本重新计算换行的触发源从来不是lines本身,而是外部传入的用户输入文本、SVG容器宽度、字体大小这些会影响换行结果的输入属性。
具体修改步骤
- 新增
useRef获取用于计算文本宽度的SVG text元素的DOM引用,用来计算文本实际渲染宽度 - 调整useEffect的依赖数组,替换为
text(用户输入的文本)、width(SVG文本容器宽度)、fontSize(字体大小)这类触发重新计算的变量 - 将原类组件中
componentDidMount和componentDidUpdate里的换行计算逻辑移到useEffect内部,计算完成后调用setLines更新结果即可
代码示例
import { useRef, useState, useEffect } from 'react'; const Text = ({ text, width, fontSize = 16 }) => { // 用于获取计算宽度的隐藏text节点的引用 const measureTextRef = useRef(null); const [lines, setLines] = useState([]); useEffect(() => { const measureEl = measureTextRef.current; // 边界判断:DOM不存在或文本为空时直接返回 if (!measureEl || !text) return; const words = text.split(' '); let currentLine = []; const calculatedLines = []; // 清空之前的测量内容 measureEl.textContent = ''; for (let i = 0; i < words.length; i++) { currentLine.push(words[i]); measureEl.textContent = currentLine.join(' '); // 当当前行宽度超过容器宽度时换行 if (measureEl.getComputedTextLength() > width) { // 把最后一个超出的单词放回下一行 currentLine.pop(); calculatedLines.push(currentLine.join(' ')); currentLine = [words[i]]; } } // 把最后剩余的内容加入行数组 calculatedLines.push(currentLine.join(' ')); // 更新lines状态,不会触发死循环 setLines(calculatedLines); // 依赖项为所有会影响换行结果的输入参数,不要加入lines }, [text, width, fontSize]); return ( <g> {/* 隐藏的测量用text节点,样式和实际渲染保持一致 */} <text ref={measureTextRef} fontSize={fontSize} style={{ visibility: 'hidden' }} /> {/* 实际渲染的换行文本 */} <text fontSize={fontSize}> {lines.map((line, idx) => ( <tspan key={idx} x={0} dy={fontSize * 1.2}>{line}</tspan> ))} </text> </g> ); };
内容的提问来源于stack exchange,提问作者Reinier68
相关产品推荐
相关产品推荐

