为啥在组件中导入 VS 硬编码时,对象数组的行为会有所不同?

Posted

技术标签:

【中文标题】为啥在组件中导入 VS 硬编码时,对象数组的行为会有所不同?【英文标题】:Why does an array of objects behave differently when imported VS hard coded in a component?为什么在组件中导入 VS 硬编码时,对象数组的行为会有所不同? 【发布时间】:2021-12-25 14:04:49 【问题描述】:

尝试坚持使用硬编码数据的工作流程作为外部参考文件,以防我想依赖像 API 这样的外部来源。鉴于当前的工作组件:

const ExpensesChart = ( expenses ) => 
  const chartDataPoints = [
     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 ,
  ]

  for (const expense of expenses) 
    const expenseMonth = expense.date.getMonth()
    chartDataPoints[expenseMonth].value += expense.amount
  

  return <Child dataPoints=chartDataPoints />


export default ExpensesChart

没有问题。当我获取对象数组chartDataPoints,并将其隔离为文件引用并导入文件时,当数据向下传递到Child时,结果会有所不同:

chartData.js:

const chartDataPoints = [
   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 ,
]

export default chartDataPoints

重写组件:

// Data
import chartDataPoints from '../../data/chartData'

const ExpensesChart = ( expenses ) => 
  for (const expense of expenses) 
    const expenseMonth = expense.date.getMonth()
    chartDataPoints[expenseMonth].value += expense.amount
  

  return <Child dataPoints=chartDataPoints />


export default ExpensesChart

我不明白为什么,或者我应该说不理解为什么行为不同。我假设当道具不同时,应该重新渲染整个组件 - 因为 for 循环应该重新运行,但后一种方法数据永远不会改变。如果 for 循环正在修改数据,我认为不需要 useStateuseEffect,但我可能是错的。

为什么对象数组的行为与组件中导入的硬编码 VS 的行为不同?


编辑:

这里的想法不同是尝试useRefuseStateuseEffect

const ExpensesChart = ( expenses ) => 
  const data = useRef(chartData)
  const [chartPoints, setChartPoints] = useState(data.current)

  useEffect(() => 
    if (expenses.length === 0) return setChartPoints(data.current)

    for (const expense of expenses) 
      data.current[expense.date.getMonth()].value += expense.amount
    
    return setChartPoints(data.current)
  , [expenses])

  return <Chart dataPoints=chartPoints />


export default ExpensesChart

但我仍然遇到问题。还包括一个 CodeSandBox:

【问题讨论】:

【参考方案1】:

在您重写的组件中,您将expenses 作为道具传递并对其进行变异。突变不应该在 React 中完成,它在这里给你带来了问题——当你改变一年的费用,然后组件由于年份的变化而重新渲染时,你传递了相同的 早先的变异数组,因此更改仍然存在。

当年份变化时,从初始空数组初始化新图表数据,并避免改变初始数组:

const ExpensesChart = ( expenses ) => 
  const [data, setData] = useState(chartData);
  useEffect(() => 
    // Expenses just changed, so set the state
    // restarting from an empty chartData array
    const newData = chartData.map(obj => ( ...obj ))
    for (const expense of expenses) 
      newData[expense.date.getMonth()].value += expense.amount;
    
    setData(newData);
  , [expenses]);
  return <Child  ... data  />;
;

export default ExpensesChart;

【讨论】:

存在同样的问题。如果我能找到时间,我将使用代码框进行更新。仅供参考,expenses 是已在父组件中过滤的数组。所以我想我可能不得不使用useStateuseEffect 添加了沙箱并再次尝试。 哦,所以并不是组件被安装在其他地方,或者被卸载并重新安装,而是在同一次安装期间年份会发生变化,您希望这会导致呈现的变化。您肯定需要状态 - 当年份发生变化时,取 empty 数组并根据需要填充它,并将其设置为新状态。 是的,我认为这是最好的,但由于某种原因,当我尝试时,我一直遇到错误。我认为 useRef 会起作用,但事实并非如此,我很难过。 其中一个问题是您对数据进行了太多拆分 - 最好只有 一个 源,然后将其传递。由于您希望显示依赖于数组中的内容,因此数组应该处于状态,而不是参考。

以上是关于为啥在组件中导入 VS 硬编码时,对象数组的行为会有所不同?的主要内容,如果未能解决你的问题,请参考以下文章

在 Next/React 组件中导入 global vs getStaticProps

为啥我不能在 react native 中导入我的自定义组件

为啥 VS Code 无法在我的程序中导入 timeit 模块?

如何在Java中导入组件对象模型(COM)?

当我使用日期类型变量而不是硬编码日期时,为啥会出现“操作数类型冲突:日期与 int 不兼容”错误?

在 vs 代码中导入的 python 模块中设置断点