React中textarea换行提交后数组未识别换行问题求助
问题描述
我有一个<textarea/>字段,按下Enter键会提交并在数组中创建新条目,按下Shift + Enter则在<textarea/>输入框内换行。但实际按下Shift+Enter换行后提交,数组并未识别到换行,渲染时换行消失。
输入时的截图:
条目添加后的截图:
可以看到,数组似乎无法识别输入中的换行。
Todobox.jsx
import React, { createContext } from 'react'; import Item from './Item'; import { useState, useContext } from 'react'; import '../App.css'; import trash from '../trash_can.png' import { ElementContext } from '../ElementContext'; export const ItemContext = createContext(); export const ItemContextProvider = ({ children }) => { const [items, setItems] = useState([]); const [itemId, setItemId] = useState(1); const [itemData, setItemData] = useState(); const [refDict, setRefDict] = useState({}); const newItemId = (items) =>{ setItemId(itemId + 1); console.log(itemId) } const newItem = (itemChange, boxid) => { newItemId(); if (!refDict[itemId]) { setItems(prev => [...prev, { itemboxid: boxid, itemdata: itemChange, itemid: itemId }]); setRefDict((prev) => ({...prev, [itemId]: true})); } console.log(items); }; const value = { items, setItems, newItem, itemId }; return( <ItemContext.Provider value={value}> {children} </ItemContext.Provider> ) }; export default function Todobox({ boxtitle, boxid }){ const { elements, setElements, newTitle } = useContext(ElementContext); const { items, setItems, newItem } = useContext(ItemContext); const [boxheader, setBoxHeader] = useState(''); const [itemChange, setItemChange] = useState(''); const handleChange = (e) => { setBoxHeader(e.target.value); } const handleKeydown = (e) => { if(e.keyCode == 13 && e.shiftKey == false){ setElements(elements.map(element => { if (element.boxid === boxid) { setBoxHeader(e.target.value) return { ...element, boxtitle: boxheader }; } else { return element; } })) e.preventDefault(); alert('Title has been set to: ' + boxheader); } } const handleDelete = (e) => { setElements(elements.filter(element => element.boxid !== boxid)) } const handleItemChange = (e) =>{ setItemChange(e.target.value); } const handleNewItem = (e) =>{ if(e.keyCode == 13 && e.shiftKey == false){ newItem(itemChange, boxid) e.preventDefault(); e.target.value = ''; } } return( <> <div className='element-box'> <img src={trash} className='element-box-trash' onClick={handleDelete}></img> <textarea className='element-title-input' placeholder='Add title...' onChange={handleChange} onKeyDown={handleKeydown} value={boxheader}></textarea> {items.map(item => { if(item.itemboxid === boxid){ return <Item key={item.itemid} itemid={item.itemid} itemdata={item.itemdata}/>; } else if(item.itemboxid !== boxid){ return null; } })} <textarea className='element-input' type='text' placeholder={`Add item... ${boxid}`} onChange={handleItemChange} onKeyDown={handleNewItem} onClick={() => {console.log(boxid)}} /> </div> </> ) }
Item.jsx
import React, { useContext } from 'react'; import '../App.css'; import { ElementContext } from '../ElementContext'; import { ItemContext } from './Todobox'; export default function Item({ itemid, itemdata }){ const { setHideModal, modals, setModals } = useContext(ElementContext); const handleNewModal = () => { setHideModal(false) setModals(prev => [...prev, { modalItemId: itemid, modalId: '1', modalData: itemdata }]); console.log(modals); }; return( <div className='item-container' onClick={handleNewModal}> <a className='item-text'>{itemdata}</a> </div> ) }
相关CSS
.item-text { padding: 2px; opacity: 1; word-wrap: break-word; }
解决方法
问题出在渲染阶段:textarea中的换行符是\n,但HTML默认不会将\n解析为换行,只会当作空格处理。有两种修复方式:
方式一:CSS保留换行
修改.item-text的CSS,添加white-space: pre-wrap;,让浏览器保留换行符并自动换行:
.item-text { padding: 2px; opacity: 1; word-wrap: break-word; white-space: pre-wrap; /* 新增该行 */ }
方式二:将换行符转为<br/>标签
在Item组件中,把itemdata里的\n替换成<br/>标签:
export default function Item({ itemid, itemdata }){ const { setHideModal, modals, setModals } = useContext(ElementContext); const handleNewModal = () => { setHideModal(false) setModals(prev => [...prev, { modalItemId: itemid, modalId: '1', modalData: itemdata }]); console.log(modals); }; // 转换换行符为br标签 const formattedText = itemdata.split('\n').map((line, index) => ( <React.Fragment key={index}> {line} {index !== itemdata.split('\n').length - 1 && <br />} </React.Fragment> )); return( <div className='item-container' onClick={handleNewModal}> <a className='item-text'>{formattedText}</a> </div> ) }
两种方式都能解决换行消失的问题,推荐用CSS方案,更简洁且符合样式与逻辑分离的原则。
内容的提问来源于stack exchange,提问作者Blazing
相关产品推荐
相关产品推荐

