
本文详解如何使用 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,或升级为受控组件+表单提交等高级场景。









