react-chartjs-2环形图标题不更新问题求助
环形图标题渲染旧值问题排查与解决
问题描述
使用react-chartjs-2实现环形图时,父组件传递的title props更新后,组件外部打印title能得到正确的新值,但插件的beforeDraw函数内部打印的却是旧的title,导致环形图中心渲染的标题始终是旧值。相关代码如下:
const Doughnut = (props) => { const { title, labels, colors, projects, percentages, width, height } = props; console.log(`title:${title}`); //this logs proper title const plugins = [ { beforeDraw: function (chart) { console.log(`title:${title}`); //this logs previous title and thus renders previous title var width = chart.width, height = chart.height, ctx = chart.ctx; ctx.restore(); var fontSize = (height / 240).toFixed(2); ctx.font = fontSize + "em sans-serif"; ctx.textBaseline = "top"; var text = `${title}`, textX = Math.round((width - ctx.measureText(text).width) / 2), textY = height / 2; ctx.fillText(title, textX, textY); ctx.save(); }, }, ]; const data = { datasets: [ { data: percentages, backgroundColor: colors, }, ], }; return ( <DoughnutChart data={data} plugins={plugins} width={width} height={height} /> ); };
问题原因
Chart.js的插件实例存在缓存机制,组件首次渲染时注册的插件会被复用。原代码中,beforeDraw函数创建时捕获了当时的title闭包值;后续title props更新时,虽然组件重新渲染生成了新的plugins数组,但Chart.js并未重新注册新的插件实例,执行的仍是第一次注册的beforeDraw函数,自然只能拿到旧的title值。
解决方案
通过useCallback和useMemo确保title更新时,beforeDraw函数和plugins数组生成新的引用,触发Chart.js重新注册插件,从而捕获最新的title值。
修改后的代码
import { useCallback, useMemo } from 'react'; import { Doughnut as DoughnutChart } from 'react-chartjs-2'; const Doughnut = (props) => { const { title, labels, colors, projects, percentages, width, height } = props; console.log(`title:${title}`); // 使用useCallback包裹beforeDraw,依赖title确保更新时生成新函数 const beforeDraw = useCallback((chart) => { console.log(`title:${title}`); const ctx = chart.ctx; const chartWidth = chart.width; const chartHeight = chart.height; ctx.restore(); const fontSize = (chartHeight / 240).toFixed(2); ctx.font = `${fontSize}em sans-serif`; ctx.textBaseline = "top"; const text = `${title}`; const textX = Math.round((chartWidth - ctx.measureText(text).width) / 2); const textY = chartHeight / 2; ctx.fillText(title, textX, textY); ctx.save(); }, [title]); // 使用useMemo生成plugins数组,依赖beforeDraw确保引用更新 const plugins = useMemo(() => [{ beforeDraw }], [beforeDraw]); const data = { datasets: [ { data: percentages, backgroundColor: colors, }, ], }; return ( <DoughnutChart data={data} plugins={plugins} width={width} height={height} /> ); };
关键修改点
- 用
useCallback包裹beforeDraw函数,将title作为依赖项,当title变化时,函数会重新创建,捕获最新的title值。 - 用
useMemo生成plugins数组,依赖beforeDraw函数,确保beforeDraw更新时,plugins数组的引用也更新,触发Chart.js重新识别插件并执行新的beforeDraw逻辑。
内容的提问来源于stack exchange,提问作者Drashti Kheni
相关产品推荐
相关产品推荐

