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

基于MERN栈的费用追踪App:实现总金额展示功能咨询

解决方案

1. 重构组件结构,将交易列表状态移至父组件

你的TranItem是单个交易项组件,无需维护transactions状态,该状态应放在父组件(比如TransactionDashboard)中统一管理,同时负责总金额计算与数据分析。

父组件示例(TransactionDashboard.js)

import React, { useState, useEffect } from 'react';
import TranItem from './TranItem';

export default function TransactionDashboard() {
  const [transactions, setTransactions] = useState([]);

  // 初始化获取所有交易数据
  useEffect(() => {
    const fetchTransactions = async () => {
      const response = await fetch('http://localhost:5000/api/transaction/gettransactions', {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
          "auth-token": localStorage.getItem('token')
        }
      });
      const json = await response.json();
      setTransactions(json);
    };
    fetchTransactions();
  }, []);

  // 删除交易方法,传递给子组件
  const deleteTransaction = async (id) => {
    const response = await fetch(`http://localhost:5000/api/transaction/deletetransaction/${id}`, {
      method: "DELETE",
      headers: {
        "Content-Type": "application/json",
        "auth-token": localStorage.getItem('token')
      }
    });
    await response.json();
    // 更新本地交易列表
    setTransactions(transactions.filter(tran => tran._id !== id));
  };

  // 计算账户总金额(根据交易类型区分收支)
  const calculateTotal = () => {
    return transactions.reduce((total, tran) => {
      return tran.type === "收入" ? total + parseFloat(tran.amount) : total - parseFloat(tran.amount);
    }, 0).toFixed(2);
  };

  // 数据分析:统计总收入/总支出
  const getIncomeExpenseStats = () => {
    const stats = { 收入: 0, 支出: 0 };
    transactions.forEach(tran => {
      const amount = parseFloat(tran.amount);
      tran.type === "收入" ? stats.收入 += amount : stats.支出 += amount;
    });
    return stats;
  };

  // 数据分析:按标签统计金额
  const getTagStats = () => {
    const tagStats = {};
    transactions.forEach(tran => {
      const amount = parseFloat(tran.amount);
      const value = tran.type === "收入" ? amount : -amount;
      tagStats[tran.tag] = (tagStats[tran.tag] || 0) + value;
    });
    return tagStats;
  };

  const incomeExpenseStats = getIncomeExpenseStats();
  const tagStats = getTagStats();

  return (
    <div className="container my-4">
      {/* 总金额展示 */}
      <div className="card mb-4">
        <div className="card-body">
          <h4 className="card-title">账户总余额</h4>
          <p className="card-text fs-3">¥{calculateTotal()}</p>
        </div>
      </div>

      {/* 数据分析模块 */}
      <div className="row mb-4">
        <div className="col-md-6">
          <div className="card">
            <div className="card-body">
              <h5 className="card-title">收支统计</h5>
              <p className="card-text">总收入: ¥{incomeExpenseStats.收入.toFixed(2)}</p>
              <p className="card-text">总支出: ¥{incomeExpenseStats.支出.toFixed(2)}</p>
            </div>
          </div>
        </div>
        <div className="col-md-6">
          <div className="card">
            <div className="card-body">
              <h5 className="card-title">按标签统计</h5>
              {Object.entries(tagStats).map(([tag, amount]) => (
                <p key={tag} className="card-text">
                  {tag}: ¥{amount.toFixed(2)}
                </p>
              ))}
            </div>
          </div>
        </div>
      </div>

      {/* 交易列表 */}
      <div className="row">
        {transactions.map(tran => (
          <TranItem key={tran._id} gettran={tran} deleteTransaction={deleteTransaction} />
        ))}
      </div>
    </div>
  );
}

2. 修改子组件TranItem.js

移除子组件内的transactions状态,直接调用父组件传递的删除方法:

import React from 'react';

export default function TranItem(props) {
  const { gettran, deleteTransaction } = props;

  return (
    <>
      <div className='col-md-3'> 
        <div className="card my-3">
          <div className="card-body">
            <h5 className="card-title">{gettran.type}</h5>
            <p className="card-text">¥{gettran.amount}</p>
            <p className="card-text">{gettran.tag}</p> 
            <p className="card-text">{gettran.date}</p> 
            <i className="fa-solid fa-trash mx-2" onClick={() => deleteTransaction(gettran._id)} />  
            <i className="fa-solid fa-pen mx-2" />  
          </div>
        </div> 
      </div>   
    </>
  );
}

关键说明

  • 总金额计算:用reduce遍历交易列表,根据交易类型(收入/支出)累加或扣除金额,最终保留两位小数。
  • 数据分析功能:
    • 收支统计:遍历交易分别统计总收入与总支出。
    • 标签统计:按交易标签分组,计算每个标签下的净金额(收入为正、支出为负)。
  • 状态管理:交易列表状态统一放在父组件,子组件仅负责渲染单个交易与触发删除操作,符合React单向数据流原则。

内容的提问来源于stack exchange,提问作者SCoder

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 01:35:58