如何在 React 中通过按钮点击动态创建并渲染列表项(li)

1次阅读

如何在 React 中通过按钮点击动态创建并渲染列表项(li)

本文详解如何使用 react 的 usestate hook 管理动态列表状态,实现点击按钮后将两个输入框的值组合为新列表项(li)并实时渲染到 ul 中,涵盖状态设计、事件处理、jsx 渲染及关键注意事项。

本文详解如何使用 react 的 usestate hook 管理动态列表状态,实现点击按钮后将两个输入框的值组合为新列表项(li)并实时渲染到 ul 中,涵盖状态设计、事件处理、jsx 渲染及关键注意事项。

在 React 应用中,动态添加 dom 元素(如

  • )不能通过直接操作 DOM 或仅返回 JSX 片段来实现——必须借助状态驱动渲染。核心逻辑是:将待显示的列表内容存储在 state 中,每次新增时更新该 state,React 便会自动重新渲染对应的 JSX。

    ✅ 正确实现步骤

    1. 声明列表状态
      使用 useState 初始化一个空数组,用于存储所有待渲染的

    2. 文本内容:
      const [values, setValues] = useState([]);
    3. 收集输入值并组合提交
      在 handleClick 中,将两个输入框的当前值(firtValue 和 secValue)拼接成字符串,并追加到 values 数组中:

      function handleClick() {   setValues(prev => [...prev, `${firtValue} ${secValue}`]); }

      ✅ 推荐使用函数式更新(prev => […])而非 concat(),更符合 React 最佳实践,避免闭包 stale state 问题。

    4. 动态渲染列表项
      将 values 数组映射为

    5. 元素列表。务必为每个
    6. 提供唯一 key
    7. (推荐使用索引 i,若需支持删除/重排,应改用唯一 ID):

      const listOfLi = values.map((value, i) => (   <li key={i}>{value}</li> ));
    8. 在 JSX 中渲染
      直接在

        内插入该变量(无需调用 listOfLi(),它已是 JSX 数组):

        <ul>{listOfLi}</ul>

    ? 原代码常见错误解析

    • ❌ listOfLi 定义为函数但未执行:{listOfLi} 传入的是函数本身,而非执行结果 → 应改为 {listOfLi()}(但更优解是直接定义为 JSX 数组)。
    • ❌ handleClick 中仅调用 listOfLi():该函数不修改状态,无法触发重新渲染。
    • ❌ 输入事件处理器命名不一致(hadnleChane / hadnleChan)且逻辑割裂:应统一管理并确保值被正确存入 state。
    • ❌ 缺少 key 属性:React 渲染列表时若无 key,可能引发性能问题或 ui 错乱。

    ✅ 完整优化代码(含关键注释)

    import { useState } from 'react';  function App() {   const [income, setIncome] = useState(0);   const expense = 10;   const balance = income - expense;   const [firtValue, setFirtValue] = useState(''); // Item 名称   const [secValue, setSecValue] = useState('');   // Amount 数值   const [values, setValues] = useState([]);        // ✅ 存储所有待渲染的 li 文本    // 输入处理:修正拼写,统一语义   const handleItemChange = (e) => setFirtValue(e.target.value);   const handleAmountChange = (e) => setSecValue(e.target.value);    const handleChange = (e) => setIncome(e.target.value);    const maxLengthCheck = (e) => {     if (e.target.value.length > e.target.maxLength) {       e.target.value = e.target.value.slice(0, e.target.maxLength);     }   };    // ✅ 点击时更新列表状态   const handleClick = () => {     if (!firtValue.trim() || !secValue.trim()) return; // 防止空项     setValues(prev => [...prev, `${firtValue} ($${secValue})`]);     // 重置输入框(可选增强体验)     setFirtValue('');     setSecValue('');   };    // ✅ 动态生成 li 列表(注意 key!)   const expenseList = values.map((item, index) => (     <li key={index}>{item}</li>   ));    return (     <div>       <header><div className="App">Expense Tracker</div></header>       <main className="main">         {/* ... 其他 UI 组件保持不变 ... */}          <div className="add-item">           Item           <input             type="text"             className="adding-input"             placeholder="Add Item"             onChange={handleItemChange}           />         </div>          <div className="add-item">           Amount           <input             type="number"             className="adding-input"             placeholder="Add Amount"             onChange={handleAmountChange}           />         </div>          <div className="add-button">           <button type="button" className="expense-button" onClick={handleClick}>             Add Expense           </button>         </div>          <div>           <ul>{expenseList}</ul>         </div>       </main>     </div>   ); }  export default App;

    ⚠️ 注意事项总结

    • 状态不可变性:永远通过 setState 更新列表,禁止直接修改数组(如 push())。
    • key 的重要性:key 必须在列表内唯一且稳定;若数据含唯一 ID(如 id 字段),优先使用 key={item.id}。
    • 空值校验:提交前检查输入有效性,避免渲染空
    • 输入重置:添加成功后清空输入框,提升用户体验(已在示例中体现)。
    • 类型安全:生产环境建议配合 typescript,为 values 添加类型注解(如 String[])。

    掌握这一模式,你就能轻松扩展功能——例如添加删除按钮(setValues(prev => prev.Filter(…)))、编辑功能或本地持久化(useEffect + localStorage)。状态即视图,这是 React 响应式开发的核心范式。

  • text=ZqhQzanResources