为什么React组件中硬编码对象数组与导入的对象数组行为不同?
问题根源
两种写法的本质差异是chartDataPoints的作用域和生命周期不同:
- 最初硬编码的版本:
chartDataPoints是组件函数内部的局部变量,组件每渲染一次就会重新创建一份全为0的初始数组,遍历累加得到的永远是当前expenses对应的正确统计值。 - 抽离到外部文件的版本:
chartDataPoints是ES模块的顶层变量,属于模块级单例,整个应用生命周期内只会初始化一次。第一次组件渲染累加后数组内的value值就已经被修改,后续所有渲染都会在之前修改后的结果上继续累加,同时直接修改导入的对象没有触发React组件重渲染的逻辑,所以会出现数据异常、看起来没更新的情况。
补充写法仍有问题的原因
- 仍然复用了导入的模块级单例作为初始值,没有每次重置为0的初始状态,累加值会持续叠加不会重置
- 直接修改
data.current的对象属性后直接把同一个引用传给setChartPoints,React对状态更新做浅比较,发现引用没有变化就会跳过重渲染,自然看不到数据更新
正确解法
把外部存储的初始数据改成返回新数组的工厂函数即可,保证每次组件渲染都能拿到全新的初始0值数组:
首先修改chartData.js:
// 导出函数而不是固定数组,每次调用返回全新的初始数据 export const getInitialChartData = () => [ { 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 }, ]
组件内不需要额外Hook,直接和最初硬编码的逻辑一致即可:
import { getInitialChartData } from '../../data/chartData' const ExpensesChart = ({ expenses }) => { // 每次渲染都拿全新的初始数组 const chartDataPoints = getInitialChartData() for (const expense of expenses) { const expenseMonth = expense.date.getMonth() chartDataPoints[expenseMonth].value += expense.amount } return <Child dataPoints={chartDataPoints} /> } export default ExpensesChart
后续要切换成API数据源,只需要修改getInitialChartData的实现,或者在组件内加请求逻辑替换初始值即可。
内容的提问来源于stack exchange,提问作者GʀᴜᴍᴘʏCᴀᴛ
相关产品推荐
相关产品推荐

