You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 05:45:06