react-chartjs-2与Chart.js实现的图表修改数值时出现两次刷新问题
问题原因与解决方案
异常原因
- 状态更新时机导致两次渲染:当
countryprop发生变化时,React会先触发一次组件重渲染,此时使用的还是上一次country对应的旧dailyData,图表会先基于旧数据更新一次图形;之后useEffect才会执行拉取新国家对应的数据,setDailyData触发第二次重渲染,此时才会更新x/y轴的标签数值,视觉上就表现为两次刷新。 - 内联data对象引用不稳定:代码中每次渲染都会给Line组件传入新生成的data对象,哪怕数据内容没有变化,新的引用也会触发react-chartjs-2内部的重绘逻辑,放大了两次更新的视觉差异。
- 初始状态设置不合理:初始
dailyData为空数组,首次渲染时解构的infected、day都是undefined,也会出现一次空渲染,之后数据返回再渲染一次的情况。
可行解决方案
可以通过以下几个措施组合解决问题:
- 新增加载状态,请求过程中展示占位内容,不要使用旧数据渲染图表,避免出现先更新旧图形的问题。
- 使用
useMemo缓存图表的data配置,只有当实际关联数据变化时才重新生成data对象,减少不必要的重绘。 - 给Line组件绑定与
country关联的key属性,切换国家时直接让图表组件重新挂载,直接用新数据渲染,跳过旧数据更新的步骤。
优化后代码示例
import { useMemo, useState, useEffect } from 'react'; import { Line } from 'react-chartjs-2'; const Chart = ({country}) => { const [dailyData,setDailyData] = useState(null); const [loading, setLoading] = useState(false); useEffect(() => { const fetchAPI = async () => { setLoading(true); const res = await fetchDailyData(country); setDailyData(res); setLoading(false); } fetchAPI(); },[country]); const chartData = useMemo(() => { if (!dailyData) return null; const { day, infected } = dailyData; return { labels: day.map(item => item), datasets: [ { data: infected.map(item => item), label: 'Infected', borderColor: '#3333ff', fill: true, } ] } }, [dailyData]); if (loading) return <div>数据加载中</div>; if (!chartData) return null; return <Line key={country} data={chartData} />; }
可选优化
如果不需要图表的入场动画,可以在Line组件的options中关闭动画,进一步避免视觉上的闪烁:
<Line key={country} data={chartData} options={{ animation: false }} />
内容的提问来源于stack exchange,提问作者guddu gupta
相关产品推荐
相关产品推荐

