如何通过WebSocket消息发送换行指令?(FastAPI后端+React前端)
环境配置
- Python FastApi 后端服务
- JS React 前端客户端
- 前端WebSocket客户端使用react-use-websocket库
问题描述
我需要通过WebSocket连接从后端API向前端客户端发送消息并向用户展示,但不知道如何在展示消息时实现换行效果。我尝试在WebSocket消息中发送\n,JS不会显示该\n字符但也不会触发换行,直接将其忽略;我也尝试发送多个空白字符,同样没有效果,无论我在API侧设置了多少空格,前端仅会展示单个空格。
代码示例
注:TextTransition组件来自react-text-transition库,该问题在标准HTML段落标签中也存在相同表现。
const {lastJsonMessage} = useWebSocket(socketURL); //... return ( <div> ... ... <div style={boxStyle}> <h1 style={{cursor: "default"}}>Message</h1> <p style={{cursor: "default"}}>━━━━━━━━━━━━━━━━━</p> <TextTransition text={lastJsonMessage ? lastJsonMessage.message : ""} style={{cursor: "default"}} springConfig={ presets.stiff } /> </div> ... ... </div> )
解决方案
该问题是HTML的默认渲染规则导致的:默认会把所有连续空白字符(换行符、制表符、多个空格)合并为单个空格,也不会将\n识别为换行标记,因此原生标签和第三方文本组件都会出现该现象。
方案1:添加CSS属性(最推荐,改动最小)
直接给展示文本的元素添加white-space: pre-wrap属性即可,该属性会保留文本中的换行符和连续空格,完全匹配你的需求,无需修改后端逻辑和数据结构。
修改后的代码如下:
<TextTransition text={lastJsonMessage ? lastJsonMessage.message : ""} style={{cursor: "default", whiteSpace: 'pre-wrap'}} springConfig={ presets.stiff } />
如果使用原生p标签展示,给p标签添加同样的style属性即可生效。
方案2:文本预处理后HTML渲染(适用于CSS方案不生效的场景)
如果TextTransition组件内部渲染逻辑不支持继承white-space属性,可以先对文本做转义处理后替换换行符为<br>标签,再用dangerouslySetInnerHTML渲染。注意如果消息内容包含用户生成内容,必须先做XSS转义避免安全风险。
代码示例:
// 文本格式化方法 const formatMessage = (msg) => { if (!msg) return "" // 先转义HTML特殊字符 const escaped = msg.replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">") // 替换换行符为br标签 return escaped.replace(/\n/g, "<br />") } // 渲染部分 <TextTransition style={{cursor: "default"}} springConfig={ presets.stiff } > <div dangerouslySetInnerHTML={{__html: formatMessage(lastJsonMessage?.message)}} /> </TextTransition>
方案3:逐行分割渲染
如果不想使用dangerouslySetInnerHTML,可以把文本按\n分割为数组,遍历渲染每一行内容,同时配合white-space: pre-wrap保留连续空格:
const messageLines = lastJsonMessage?.message?.split('\n') || [] // 渲染部分 <TextTransition style={{cursor: "default", whiteSpace: 'pre-wrap'}} springConfig={ presets.stiff } > {messageLines.map((line, idx) => <div key={idx}>{line}</div>)} </TextTransition>
内容的提问来源于stack exchange,提问作者Alperen Ozturk

