React自定义Bar组件触发无限渲染导致浏览器崩溃问题排查
无限渲染问题修复方案
问题根源
- 核心原因:自定义Bar组件中完全没必要用
useState存储Chart实例,你代码中并未消费这个状态值,每次调用setChartInstance都会触发组件重渲染,形成循环触发链:执行useEffect创建实例→调用setState触发重渲染→useEffect依赖变更再次执行→回到第一步 - 次要问题:useEffect依赖数组错误加入了整个
chartContainerref对象,同时未添加清理函数销毁旧的Chart实例,也未判断自定义图表类型是否已经注册,重复修改Chart全局配置也会加重异常。
你之前猜测的const声明组件和问题无关,React组件不管是函数声明还是const声明的箭头函数组件,都不会引发无限渲染,完全是自定义Bar组件内部的状态使用和依赖配置错误导致的问题。
修复后的Bar组件代码
/* eslint-disable prefer-rest-params */ import React, { useEffect, useRef } from 'react'; import { Chart } from 'chart.js'; import { barChartOptions } from './config'; // 自定义图表类型只需要注册一次,放到组件外避免重复注册 let shadowControllerRegistered = false; const Bar = ({ data, shadow = false }) => { const chartContainer = useRef(null); // 用ref存实例,不需要用state,不会触发重渲染 const chartInstanceRef = useRef(null); useEffect(() => { // 先销毁旧的实例,避免重复创建 if (chartInstanceRef.current) { chartInstanceRef.current.destroy(); } if (chartContainer.current) { // 只注册一次自定义阴影柱状图类型 if (shadow && !shadowControllerRegistered) { Chart.defaults.global.datasets.barWithShadow = Chart.defaults.global.datasets.bar; Chart.defaults.barWithShadow = Chart.defaults.bar; Chart.controllers.barWithShadow = Chart.controllers.bar.extend({ draw(ease) { Chart.controllers.bar.prototype.draw.call(this, ease); const { chart: { ctx }, } = this; ctx.save(); ctx.shadowColor = 'rgba(0,0,0,0.2)'; ctx.shadowBlur = 7; ctx.shadowOffsetX = 5; ctx.shadowOffsetY = 7; ctx.responsive = true; Chart.controllers.bar.prototype.draw.apply(this, arguments); ctx.restore(); }, }); shadowControllerRegistered = true; } const context = chartContainer.current.getContext('2d'); // 实例存到ref里,不要用state存,避免触发重渲染 chartInstanceRef.current = new Chart(context, { type: shadow ? 'barWithShadow' : 'bar', options: barChartOptions, data, }); } // 清理函数:组件卸载或者依赖变更时销毁实例 return () => { if (chartInstanceRef.current) { chartInstanceRef.current.destroy(); } }; // 依赖只留需要监听变化的data和shadow,不需要加ref对象 }, [data, shadow]); return <canvas ref={chartContainer} />; }; export default Bar;
内容的提问来源于stack exchange,提问作者randomG765
相关产品推荐
相关产品推荐

