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

React传递对象数组类型props给子组件时值翻倍异常

问题背景

实现月度支出进度条功能,共涉及Chart、Bar两个组件,其中Chart组件初始实现代码如下:

import Bar from "./Bar";

const INIT_MONTH_EXPENSES = [
  { label: "Jan", value: 0 },
  { label: "Feb", value: 0 },
  { label: "Mar", value: 0 },
  { label: "Apr", value: 0 },
  { label: "May", value: 0 },
  { label: "Jun", value: 0 },
  { label: "Jul", value: 0 },
  { label: "Aug", value: 0 },
  { label: "Sep", value: 0 },
  { label: "Oct", value: 0 },
  { label: "Nov", value: 0 },
  { label: "Dec", value: 0 },
];

const Chart = (props) => {
  const totalExpenseAmountOfYear = props.items.reduce((total, item) => {
    total = +total + +item.amount;
    return total;
  }, 0);

  for (const expense of props.items) {
    const expenseMonth = expense.date.getMonth();
    INIT_MONTH_EXPENSES[expenseMonth].value += expense.amount;
  }
  //INIT_MONTH_EXPENSES[2].value give me the expected value but props.expenses[2].value in the Bar component give me a wrong value(actually doubled value) 
  return (
    <div className="bg-pink-200 w-full h-[150px] p-4 mb-8 flex">
      <Bar
        expenses={INIT_MONTH_EXPENSES}
        totalAmount={totalExpenseAmountOfYear}
      />
    </div>
  );
};

export default Chart;

遇到的异常现象:

  • 在Chart组件内部直接读取INIT_MONTH_EXPENSES[2].value可以得到预期正确值
  • 将INIT_MONTH_EXPENSES作为expenses属性传递给Bar子组件后,Bar组件内读取props.expenses拿到的数值为预期值的两倍,结果错误
问题根因

INIT_MONTH_EXPENSES是定义在组件外部的模块级变量,属于全局共享引用:

  1. React组件每次触发重渲染时,都会重新执行组件内部的逻辑,写在组件内的for循环累加逻辑会反复执行
  2. 由于没有在每次累加前重置月度数据的value为0,每次重渲染都会在上一次计算的value基础上继续累加数值
  3. JS中对象和数组是引用传递,传给Bar组件的是这个全局数组的引用,当全局数组被反复修改累加时,子组件拿到的props值就会出现翻倍、多倍增长的错误
  4. 在Chart组件里打印时值看起来正确,只是因为打印时机刚好在本轮for循环执行完成后,还没触发下一轮重渲染累加而已
修复方案
  • 将月度初始数据的定义移到Chart组件内部,保证每次组件渲染时都会生成一份全新的、value全为0的初始数据,避免全局变量残留旧值
  • 不要直接修改外部共享的对象/数组,所有计算逻辑基于当前渲染周期内的临时数据完成,避免引用共享导致的异常

修复后的代码如下:

import Bar from "./Bar";

const Chart = (props) => {
  // 每次组件渲染重新生成初始月度数据,初始值全为0
  const monthExpenses = [
    { label: "Jan", value: 0 },
    { label: "Feb", value: 0 },
    { label: "Mar", value: 0 },
    { label: "Apr", value: 0 },
    { label: "May", value: 0 },
    { label: "Jun", value: 0 },
    { label: "Jul", value: 0 },
    { label: "Aug", value: 0 },
    { label: "Sep", value: 0 },
    { label: "Oct", value: 0 },
    { label: "Nov", value: 0 },
    { label: "Dec", value: 0 },
  ];

  const totalExpenseAmountOfYear = props.items.reduce((total, item) => {
    return +total + +item.amount;
  }, 0);

  for (const expense of props.items) {
    const expenseMonth = expense.date.getMonth();
    monthExpenses[expenseMonth].value += expense.amount;
  }

  return (
    <div className="bg-pink-200 w-full h-[150px] p-4 mb-8 flex">
      <Bar
        expenses={monthExpenses}
        totalAmount={totalExpenseAmountOfYear}
      />
    </div>
  );
};

export default Chart;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:45:38