在开发后台管理系统或内容展示类页面时,经常遇到这样的场景:接口返回一段用换行符分隔的长文本,比如商品介绍、日志记录、用户留言等,产品经理要求把每一行渲染成一个列表项。很多初学者的第一反应是直接把字符串塞进一个<p>标签里,结果发现换行符在页面上毫无效果,所有内容挤成一行。这篇文章就来详细讲解如何在React中把多行字符串正确地渲染成HTML列表,并分析其中的细节和常见坑。

一、基本思路:用split分割字符串再用map渲染列表
React渲染列表的标准做法是使用数组的map方法,而多行字符串本质上就是用换行符连接的多段文本,所以核心思路分两步:第一步用split把字符串按换行符拆成数组,第二步用map把数组每一项映射成一个<li>元素。
先看一个最简单的例子:
function TextList({ text }) {
// 按换行符拆分成数组
const lines = text.split('\n');
return (
<ul>
{lines.map((line, index) => (
<li key={index}>{line}</li>
))}
<ul>
);
}这段代码在大多数情况下能正常工作。假设传入的字符串是"第一行\n第二行\n第三行",页面就会渲染出三个列表项。这里有两个细节值得注意:一是key属性是React列表渲染的硬性要求,静态展示场景用索引作key没有问题,但如果列表后续会增删排序,建议用唯一ID;二是split返回的数组中可能出现空字符串,后面会专门讨论怎么处理。
二、处理换行符差异和空行等边界情况
直接用split('\n')有一个隐患:不同操作系统的换行符并不统一。Linux和macOS使用\n,而Windows使用\r\n。如果字符串来自Windows系统编辑的文件,直接按\n分割后,每一行末尾会残留一个\r字符,肉眼看不到,但在做字符串比较、长度计算时会出问题。稳妥的做法是先用正则表达式统一处理:
function TextList({ text }) {
// 同时兼容 \n 和 \r\n,并过滤掉纯空行
const lines = text
.split(/\r?\n/)
.filter(line => line.trim() !== '');
return (
<ol>
{lines.map((line, index) => (
<li key={index}>{line}</li>
))}
</ol>
);
}正则/\r?\n/表示匹配可选的\r后跟\n,这样两种换行风格都能正确分割。加上filter过滤空行后,字符串末尾多余的换行符也不会产生空列表项。不过是否要过滤空行要看业务需求:如果空行本身有分隔段落的意义(比如诗歌的节与节之间),就应该保留空行,此时可以把空行渲染成一个带间距的占位元素,而不是简单丢弃。
还有一个容易忽略的场景是字符串中的行内空格。HTML默认会合并连续空格,如果某行文本有对齐需求(比如代码片段或表格数据),单纯用<li>展示会丢失缩进。解决办法是给列表项加上white-space: pre-wrap样式,让浏览器保留文本中的空白字符:
<li key={index} style={{ whiteSpace: 'pre-wrap' }}>{line}</li>三、ul、ol还是p标签?根据语义选择合适的容器
渲染多行文本时,容器的选择并不随意,应该根据内容语义决定。<ul>无序列表适合各项之间没有顺序关系的文本,比如功能点罗列、标签展示;<ol>有序列表适合有先后顺序的内容,比如操作步骤、排行榜,浏览器会自动加上序号;如果内容只是换行分隔的普通段落,用列表反而在语义上不准确,此时更适合把每一行映射成独立的<p>标签,或者直接在一个容器里用CSS实现换行效果。
如果是纯展示场景,其实还有一种零JS的方案:保留原始字符串,直接放进一个带样式的元素里:
<div style={{ whiteSpace: 'pre-line' }}>{text}</div>pre-line会让浏览器把文本中的换行符识别为真实换行,同时仍然合并多余空格。这种写法最简单,性能也最好,缺点是拿不到每一行的DOM结构,无法给单行加样式、绑定事件或做条件高亮。所以选择方案时可以遵循一个简单原则:需要逐行操作就用split + map渲染列表,纯静态展示就用pre-line。
四、警惕dangerouslySetInnerHTML带来的安全风险
网上有些教程会推荐用split配合<br />拼接HTML字符串,再通过dangerouslySetInnerHTML注入,这种做法需要非常谨慎。如果字符串来源不可信(比如用户输入的评论),攻击者可以注入恶意脚本,造成XSS跨站脚本攻击。看一个危险的例子:
// 危险写法,存在XSS风险
const html = text.split('\n').map(line => `<p>${line}</p>`).join('');
<div dangerouslySetInnerHTML={{ __html: html }} />假如text中包含类似<img src=x onerror=alert(1)>的内容,这段代码就会执行恶意逻辑。React默认对插值内容做HTML转义,而dangerouslySetInnerHTML绕过了这层保护,等于手动打开了安全漏洞。正确的做法始终是使用React的JSX插值渲染纯文本,让框架自动处理转义。只有在字符串确实由可信源生成且必须包含HTML标签时,才考虑配合DOMPurify这类库做净化后再注入。
总结一下,在React中把多行字符串渲染成HTML列表,标准解法就是split(/\r?\n/)分割加map生成<li>,中间注意处理换行符兼容、空行过滤和key设置,同时坚决避免用dangerouslySetInnerHTML处理不可信文本。掌握这些要点,无论后端返回什么格式的多行数据,都能在前端优雅地展示出来。
React多行字符串渲染HTML列表split换行符修改时间:2026-09-14 23:04:37