
本文详解如何使用 react 的 usestate hook 管理动态列表状态,通过点击按钮将两个输入框的值组合成新列表项(li),并安全、高效地渲染到 ul 中。涵盖状态设计、事件处理、jsx 渲染及关键注意事项。
本文详解如何使用 react 的 usestate hook 管理动态列表状态,通过点击按钮将两个输入框的值组合成新列表项(li),并安全、高效地渲染到 ul 中。涵盖状态设计、事件处理、jsx 渲染及关键注意事项。
在 React 应用中,动态添加 dom 元素(如
✅ 核心思路
- 使用 useState 维护一个数组状态(如 values),用于存储所有待渲染的列表内容;
- 输入框通过 onChange 实时更新对应字段(firtValue 和 secValue);
- 点击按钮时,将二者拼接后追加至 values 数组;
- 在 JSX 中通过 .map() 将 values 映射为
- 元素列表,并确保每个 li 拥有唯一 key。
✅ 完整代码实现
import { useState } from 'react'; function App() { const [income, setIncome] = useState(0); const expense = 10; const balance = income - expense; const [firtValue, setFirtValue] = useState(''); const [secValue, setSecValue] = useState(''); // ✅ 新增:用于存储所有待渲染的 li 文本的数组状态 const [values, setValues] = useState([]); const hadnleChane = (event) => setSecValue(event.target.value); const hadnleChan = (event) => setFirtValue(event.target.value); const handleChange = (event) => setIncome(event.target.value); const maxLengthCheck = (object) => { if (object.target.value.length > object.target.maxLength) { object.target.value = object.target.value.slice(0, object.target.maxLength); } }; // ✅ 正确的点击处理:更新状态,触发重渲染 const handleClick = () => { if (firtValue.trim() && secValue.trim()) { setValues(prev => [...prev, `${firtValue} — $${secValue}`]); // 可选:清空输入框 setFirtValue(''); setSecValue(''); } }; // ✅ 正确渲染:基于 values 数组生成 li 列表 const listOfLi = values.map((value, index) => ( <li key={index}>{value}</li> )); return ( <div> <header> <div className="App">Expense Tracker</div> </header> <main className="main"> <div className="income-box"> <div className="income"> Income <div className="numbers">{income}$</div> </div> <div className="expense"> Expense <div className="numbers">{expense}$</div> </div> </div> <div className="income-input"> <input type="number" min="0" maxLength="8" onInput={maxLengthCheck} className="input" placeholder="Enter your Income" onChange={handleChange} /> </div> <div className="total-balance">Total Balance: {balance}$</div> <div className="add-item"> Item <input type="text" className="adding-input" placeholder="Add Item" onChange={hadnleChane} /> </div> <div className="add-item"> Amount <input type="number" className="adding-input" placeholder="Add Amount" onChange={hadnleChan} /> </div> <div className="add-button"> <button type="button" className="expense-button" onClick={handleClick} > Add Expense </button> </div> <div> <ul>{listOfLi}</ul> </div> </main> </div> ); } export default App;
⚠️ 关键注意事项
- 不要在 onClick 中直接调用 JSX 函数(如原代码中的 listOfLi()):这仅返回一个 React 元素对象,不会影响 DOM,也不会触发渲染。
- 必须使用 key 属性:.map() 渲染列表时,key 是 React 识别元素身份的必要标识;推荐使用稳定索引(如 index)或更佳的唯一 ID(若数据支持)。
- 避免直接修改状态数组:始终使用 setValues(prev => […prev, newItem]) 等不可变方式更新,防止状态失效。
- 增强健壮性:添加空值校验(如 trim() 判断),避免插入空白项;可选地在添加后重置输入框,提升用户体验。
- 命名规范建议:firtValue 应为 firstValue(原文拼写错误),实际项目中请修正以保障可维护性。
掌握这一模式后,你可轻松扩展功能——例如支持删除某项(通过 Filter)、编辑、持久化到 localStorage,或升级为受控组件+表单提交等高级场景。