React中ChartJS硬编码数据正常 传入数组变量时图表不加载数据
React项目ChartJS Line组件动态数组传值不渲染问题解决
问题表现
- 硬编码数据传入Line组件时,折线图可正常渲染,代码如下:
<Line data={{ labels: ['2022-07-04', '2022-07-03', '2022-07-02', '2022-06-27'], datasets: [ { label: 'My First dataset', fill: false, lineTension: 0.1, backgroundColor: 'rgba(75,192,192,0.4)', borderColor: 'rgba(75,192,192,1)', borderCapStyle: 'butt', borderDash: [], borderDashOffset: 0.0, borderJoinStyle: 'miter', pointBorderColor: 'rgba(75,192,192,1)', pointBackgroundColor: '#fff', pointBorderWidth: 1, pointHoverRadius: 5, pointHoverBackgroundColor: 'rgba(75,192,192,1)', pointHoverBorderColor: 'rgba(220,220,220,1)', pointHoverBorderWidth: 2, pointRadius: 1, pointHitRadius: 10, data: [3.1, 3.1, 3.1, 2.74] }, ] }} />
- 将
labels、datasets.data替换为push方法填充的dateArray、priceArray变量时,图表无法填充数据;控制台打印两个数组的内容和硬编码值完全一致,对应代码如下:
<Line data={{ labels: dateArray, datasets: [ { label: 'My First dataset', fill: false, lineTension: 0.1, backgroundColor: 'rgba(75,192,192,0.4)', borderColor: 'rgba(75,192,192,1)', borderCapStyle: 'butt', borderDash: [], borderDashOffset: 0.0, borderJoinStyle: 'miter', pointBorderColor: 'rgba(75,192,192,1)', pointBackgroundColor: '#fff', pointBorderWidth: 1, pointHoverRadius: 5, pointHoverBackgroundColor: 'rgba(75,192,192,1)', pointHoverBorderColor: 'rgba(220,220,220,1)', pointHoverBorderWidth: 2, pointRadius: 1, pointHitRadius: 10, data: priceArray }, ] }} />
已知日期、价格数组为倒序,该逻辑不影响功能,无需针对该点调整。
根本原因
React默认通过浅比较判断是否触发组件重渲染:直接调用push修改原数组时,数组的内存引用地址不会发生变化,React会判定数据未更新,不会触发Line组件重绘。
控制台打印数组这类引用类型值时,展示的是控制台被打开时该引用指向的最终内容,所以哪怕打印结果和硬编码完全一致,组件首次挂载时拿到的很可能是空数组,后续也没有收到数据更新通知。
修复方案
禁止直接修改原数组,通过生成新数组引用的方式更新数据,触发组件重渲染:
- 使用
useState管理数组状态时,通过展开运算符返回新数组完成更新
const [dateArray, setDateArray] = useState([]) const [priceArray, setPriceArray] = useState([]) // 错误写法:直接push修改原数组,不会触发重渲染 // dateArray.push('2022-07-04') // priceArray.push(3.1) // 正确写法:返回新数组,引用变化触发重渲染 setDateArray([...dateArray, '2022-07-04']) setPriceArray([...priceArray, 3.1])
- 批量获取数据后再渲染图表时,直接通过map等遍历方法生成全新数组赋值,不要先初始化空数组再逐个push
// 数据处理完成后直接生成新数组传入 const dateArray = res.data.dateList.map(item => dayjs(item).format('YYYY-MM-DD')) const priceArray = res.data.priceList.map(item => Number(item))
如果按上述方式调整后仍不渲染,额外检查两个数组长度是否完全一致,价格数组内的值是否为Number类型(不要传入字符串格式的数字)。
内容的提问来源于stack exchange,提问作者sneaker
相关产品推荐
相关产品推荐

