React开发支出追踪器时如何通过map多次渲染Expense组件
问题排查与修正方案
你当前代码存在4处核心逻辑错误,对应修正方案如下:
核心问题点
- 状态逻辑混淆:将「当前填写的表单临时状态」和「已提交的支出列表状态」合并为同一个state,导致结构混乱
- 状态更新错误:初始
formValues声明为数组结构,但onHandleChange更新时传入了对象,直接把数组覆盖为对象,无法遍历生成多条组件 - 遍历逻辑错误:使用
Object.keys(formValues)遍历拿到的是键名而非真实的支出条目数据,且map回调没有return组件,最终渲染结果为空 - props传值错误:将遍历得到的键名字符串传给
Expense组件的formValues属性,组件无法读取到对应字段值
完整修正代码
1. 状态与事件逻辑调整
import { useState } from 'react'; import Expense from './Expense'; // 单条支出的初始模板 const initialValues = {payment: '', purchase: '', date:'', location: '', price: ''}; function ExpenseTracker() { // 拆分两个状态:当前填写的表单临时值 + 已提交的所有支出列表 const [currentForm, setCurrentForm] = useState(initialValues); const [expenseList, setExpenseList] = useState([]); // 表单输入同步更新临时状态 const onHandleChange = (e) => { const value = e.target.value; setCurrentForm({ ...currentForm, [e.target.name]: value }); } // 提交表单:把当前填写的支出加入列表,清空表单 const onSubmit = (e) => { e.preventDefault(); setExpenseList([...expenseList, {...currentForm}]); setCurrentForm(initialValues); }
2. 渲染逻辑调整
return ( <> {/* 表单部分 */} <form onSubmit={onSubmit}> <input name="payment" value={currentForm.payment} onChange={onHandleChange} placeholder="支付方式" required /> <input name="purchase" value={currentForm.purchase} onChange={onHandleChange} placeholder="购买商品" required /> <input name="date" type="date" value={currentForm.date} onChange={onHandleChange} required /> <input name="location" value={currentForm.location} onChange={onHandleChange} placeholder="消费地点" required /> <input name="price" type="number" value={currentForm.price} onChange={onHandleChange} placeholder="消费金额" required /> <button type="submit">添加支出记录</button> </form> {/* 支出列表表格 */} <table className="expense-container"> <tbody className='expense-list'> {/* 直接遍历支出列表,每个条目对应一个Expense组件,添加唯一key */} {expenseList.map((expenseItem, index) => ( <Expense key={index} formValues={expenseItem} /> ))} </tbody> </table> </> ) } export default ExpenseTracker;
3. Expense组件无需修改,保持原有逻辑即可
function Expense({ formValues }) { return( <tr className='tableRow expense'> <td className="mr-2">{formValues.payment}</td> <td className="mr-1">{formValues.purchase}</td> <td className="mr-1">{formValues.date}</td> <td className="mr-1">{formValues.location}</td> <td className="mr-1">{formValues.price}</td> </tr> ) } export default Expense;
内容的提问来源于stack exchange,提问作者OtakuCode
相关产品推荐
相关产品推荐

