新闻中心
React 中 ECharts 多实例窗口调整大小失效的解决方案

在 react 应用中渲染多个 echarts 图表时,如果仅使用 window.onresize 监听窗口大小变化来触发图表重绘,会导致只有最后一个注册的图表能够响应。这是因为 window.onresize 是一个事件属性,每次赋值都会覆盖前一个。解决此问题的正确方法是使用 window.addeventlistener 为每个图表实例添加独立的 resize 事件监听器,并确保在组件卸载时清理这些监听器,从而保证所有图表都能正确响应窗口大小变化。
理解多 ECharts 实例的尺寸调整问题
在 React 应用中集成 ECharts 图表时,为了确保图表能够适应不同屏幕尺寸或容器大小的变化,通常需要监听浏览器窗口的 resize 事件,并在事件触发时调用 ECharts 实例的 resize() 方法。然而,当页面中存在多个 ECharts 组件实例时,如果每个组件都尝试通过直接赋值 window.onresize 来注册其重绘逻辑,就会遇到一个常见问题:只有最后一个被渲染的 ECharts 图表能够响应窗口大小变化,而之前的图表则保持不变。
问题分析:window.onresize 的局限性
window.onresize 是一个 DOM 事件属性,它只能绑定一个事件处理函数。这意味着每当一个组件执行 window.onresize = function() { ... } 时,它都会覆盖之前任何组件设置的 onresize 处理函数。因此,当页面中有多个 SimpleLine 组件实例时,它们会依次设置自己的 onresize 处理函数,最终只有最后一个组件的 onresize 会生效。
原始的 SimpleLine 组件中存在问题的代码片段如下:
useEffect(() => {
window.onresize = function () {
chartInstance2.resize();
};
return () => {
chartInstance2 && chartInstance2.dispose();
};
}, []);这段代码在每次组件挂载时都会尝试重新赋值 window.onresize,导致了上述问题。
解决方案:使用 window.addEventListen
er
为了解决 window.onresize 的覆盖问题,我们应该使用 window.addEventListener 方法。addEventListener 允许为同一个事件类型注册多个事件处理函数,而不会互相覆盖。每个组件实例都可以独立地注册自己的 resize 事件处理函数,确保所有图表都能在窗口大小变化时正确重绘。
修改后的 useEffect 钩子应该如下所示:
useEffect(() => {
// 定义一个事件处理函数
const handleResize = () => {
chartInstance2 && chartInstance2.resize();
};
// 添加事件监听器
window.addEventListener("resize", handleResize);
// 组件卸载时清理 ECharts 实例并移除事件监听器
return () => {
window.removeEventListener("resize", handleResize);
chartInstance2 && chartInstance2.dispose();
};
}, [chartInstance2]); // 确保当 chartInstance2 变化时重新注册监听器在这个改进后的代码中:
BrandCrowd
一个在线Logo免费设计生成器
200
查看详情
- 我们定义了一个名为 handleResize 的函数来封装 chartInstance2.resize() 调用。
- window.addEventListener("resize", handleResize) 为当前组件实例添加了一个 resize 事件监听器。
- 在 useEffect 的清理函数中,我们通过 window.removeEventListener("resize", handleResize) 移除了对应的事件监听器。这一步至关重要,它可以防止内存泄漏,并确保当组件卸载时,其事件处理函数不再被调用。
- 将 chartInstance2 添加到 useEffect 的依赖数组中,以确保当图表实例本身发生变化时(尽管在这个例子中不太可能,但这是一个良好的实践),事件监听器能够被正确地重新注册。
完整的 ECharts 组件示例
结合上述修改,一个能够正确处理多个 ECharts 实例尺寸调整的 React 组件 SimpleLine.js 示例如下:
import React, { useRef, useEffect, useState } from "react";
import * as echarts from "echarts";
// 示例数据,实际应用中可能从 props 或 API 获取
let xAxisDatas = [
"Jan 01", "Jan 02", "Jan 03", "Jan 04", "Jan 05", "Jan 06", "Jan 07", "Jan 08", "Jan 09", "Jan 10",
"Jan 11", "Jan 12", "Jan 13", "Jan 14", "Jan 15", "Jan 16", "Jan 17", "Jan 18", "Jan 19", "Jan 20",
"Jan 21", "Jan 22", "Jan 23", "Jan 24", "Jan 25", "Jan 26", "Jan 27", "Jan 28", "Jan 29", "Jan 30", "Jan 31",
// ... 更多数据
];
let data = [
{
name: 'A',
type: "line",
smooth: false,
showSymbol: true,
symbolSize: 0.1,
itemStyle: { color: '#0F4C5C' },
lineStyle: { width: 5 },
areaStyle: {
color: 'transparent',
opacity: 0.5,
},
label: {
show: true,
position: 'top',
color: "#0F4C5C",
fontSize: 15,
fontWeight: 'Bold',
},
data: [
31, 49, 36, 36, 30, 36, 36, 34, 38, 40, 34, 36, 32, 35, 34, 35, 32, 30, 37, 32, 40, 40, 33, 39,
31, 37, 34, 35, 38, 37, 33, 32, 38, 33, 35, 37, 37, 39, 33, 39, 45, 50, 51, 38, 39, 34, 32, 39,
31, 34, 31, 35, 34, 33, 30, 38, 38, 33, 68, 33, 35, 37, 32, 38, 30, 31, 30, 30, 31, 38, 39, 22,
32, 30, 35, 35, 37, 40, 31, 38, 34, 30, 36, 30, 34, 61, 31, 40, 40, 32, 35, 33, 39, 30, 34, 33,
],
markLine: {
silent: true,
lineStyle: {
color: '#5d6664'
},
data: [{ yAxis: 38 }]
}
}
];
var option1 = {
textStyle: {
color: "#545454",
fontFamily: "Source Han Sans",
fontWeight: "lighter",
fontSize: '15',
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
crossStyle: {
color: "#999"
}
}
},
legend: {
data: ['A'],
left: "50%",
top: "2%",
itemWidth: 10,
itemHeight: 5
},
xAxis: {
type: "category",
data: xAxisDatas,
axisLabel: {
margin: "10"
},
name: "xAxisName",
nameLocation: "center",
nameGap: 30,
nameTextStyle: {
padding: [5, 0, 0, 0]
},
axisTick: {
alignWithLabel: true,
inside: true
}
},
yAxis: {
name: "",
type: "value",
splitLine: {
show: false
}
},
dataZoom: [
{
show: false,
realtime: true,
start: 50,
end: 100
},
{
type: "inside",
realtime: true,
start: 50,
end: 100
}
],
grid: {
left: '2%',
top: '10%',
right: '2%',
bottom: '12%'
},
series: data,
};
function SimpleLine() {
const chartRef = useRef(null);
// 使用 useState 存储 chartInstance,确保其在组件生命周期内稳定
const [chartInstance, setChartInstance] = useState(null);
// 初始化图表实例
useEffect(() => {
if (chartRef.current) {
const renderedChartInstance = echarts.getInstanceByDom(chartRef.current);
let instance;
if (renderedChartInstance) {
instance = renderedChartInstance;
} else {
instance = echarts.init(chartRef.current);
}
instance.setOption(option1, true);
setChartInstance(instance); // 将实例保存到 state
}
// 组件卸载时清理 ECharts 实例(如果尚未通过 resize 监听器清理)
return () => {
// 这里的清理是备用,主要清理在 resize 监听器中进行
// chartInstance && chartInstance.dispose();
};
}, []); // 空依赖数组确保只在组件挂载时执行一次
// 监听窗口 resize 事件
useEffect(() => {
if (!chartInstance) return; // 确保 chartInstance 已经初始化
const handleResize = () => {
chartInstance.resize();
};
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
chartInstance.dispose(); // 在组件卸载时销毁 ECharts 实例
};
}, [chartInstance]); // 依赖 chartInstance,确保当它被设置后才注册监听器
return (
<div ref={chartRef} style={{ width: "100%", height: "400px" }}></div>
);
}
export default SimpleLine;注意事项与最佳实践
事件监听器的清理: 在 React 的 useEffect 钩子中,如果添加了事件监听器,务必在返回的清理函数中移除它 (removeEventListener)。这可以有效防止内存泄漏,尤其是在组件频繁挂载和卸载的场景中。
chartInstance 的管理: 将 ECharts 实例存储在 React 的 useState 或 useRef 中是推荐的做法。useState 更适用于需要在依赖项中使用的场景,而 useRef 则适用于不需要触发组件重新渲染的引用。在本例中,使用 useState 并将其作为 useEffect 的依赖项,可以确保当图表实例准备好后才注册 resize 监听器。
-
防抖 (Debounce) 或节流 (Throttle): 窗口 resize 事件在拖动窗口时会频繁触发。为了优化性能,避免 ECharts 图表过于频繁地重绘,可以考虑对 handleResize 函数进行防抖或节流处理。例如,使用 Lodash 库的 debounce 函数:
import { debounce } from 'lodash'; // ... useEffect(() => { if (!chartInstance) return; const handleResize = () => { chartInstance.resize(); }; // 使用 debounce 包装事件处理函数,例如每 100ms 触发一次 const debouncedHandleResize = debounce(handleResize, 100); window.addEventListener("resize", debouncedHandleResize); return () => { window.removeEventListener("resize", debouncedHandleResize); debouncedHandleResize.cancel(); // 取消任何待处理的防抖调用 chartInstance.dispose(); }; }, [chartInstance]); ResizeObserver (高级): 对于更复杂的布局或需要监听特定 DOM 元素尺寸变化的场景,可以考虑使用 ResizeObserver API。它允许您在元素的尺寸发生变化时得到通知,而不仅仅是窗口的尺寸变化。这在图表容器本身尺寸变化(而非窗口尺寸变化)时重绘图表非常有用。
通过采纳 window.addEventListener 和正确的 useEffect 清理机制,可以确保在 React 应用中渲染的多个 ECharts 图表都能够独立且正确地响应窗口大小变化,从而提供更稳定和响应式的用户体验。
以上就是React 中 ECharts 多实例窗口调整大小失效的解决方案的详细内容,更多请关注其它相关文章!
# 在这个
# 中国网站建设推广
# 网站优化需要哪些条件
# 孝感抖音seo搜索公司
# 奎屯网站建设推广公司
# 衡水教育网站推广方案
# 甘肃营销网站推广销售
# 张家界可靠营销推广招聘
# 漯河企业号推广营销费用
# 奉贤网站建设系统
# 如何快速提升seo排名软件
# 表单
# 后才
# 适用于
# 防抖
# react
# 移除
# 绑定
# 自己的
# 是一个
# 多个
# red
# 重绘
# 常见问题
# win
# echarts
# 浏览器
# go
# js
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
Win11怎么用U盘重装系统 Win11制作启动盘并重装系统完整教程【详解】
TikTok评论显示延迟如何处理 TikTok评论刷新优化方法
如何仅使用CSS更改登录界面背景图像图标的颜色
如何有效阻止外部脚本意外修改内联样式的高度属性
b站如何看历史记录_b站观看历史找回方法
学习通网页版官方登录 超星学习通电脑端入口指南
J*a TimerTask文件监控:HashMap状态管理与常见陷阱规避指南
Python实时数据流中的动态最值查找策略
CSS布局中意外空白:解决padding-top导致的顶部间距问题
支付宝碰一碰设备是REDMI手机吗 博主拆机辟谣:处理器、内存都不一样
在Go Martini框架中高效服务动态生成图像的实践指南
大象笔记网页版入口 印象笔记网页版登录入口
HTML长属性值处理:表单action路径优化与代码规范应对
在J*a中如何开发简易仓库管理与库存统计_仓库管理库存统计项目实战解析
CSS子选择器:如何区分并样式化嵌套列表的子层级
俄罗斯Yandex免登录入口_Yandex搜索引擎官网一键直达
如何使用纯J*aScript判断Input元素是否在特定类容器内
漫蛙漫画官方首页 漫蛙2漫画在线阅读入口
CSS Flexbox与媒体查询:实现响应式布局中元素的并排与堆叠
支付宝如何管理隐私设置_支付宝隐私保护的配置技巧
QQ邮箱电脑版登录入口_QQ邮箱官方网站登录平台
Win10如何开启蓝牙功能_Windows10找不到蓝牙开关解决方法
LocoySpider如何部署到云服务器_LocoySpider云部署的远程配置
c++中的std::forward_list和std::list有什么不同_c++ forward_list与list区别分析
Golang如何使用bytes.Split分割字节切片_Golang bytes切片分割方法
J*aScript数据结构转换:将对象数组按类别分组
如何使用Rector自动化升级旧代码_通过Composer安装和配置Rector进行代码重构
AI泡沫首次被“刺破”:GPU十年都无法存活!
c++中的std::launder有什么实际用途_c++对象生命周期与指针优化
Golang如何安装Swagger工具_GoSwagger文档生成环境
Windows 11怎么彻底关闭定位_Windows 11服务中禁用Geolocation
Safari自带网页翻译功能怎么用 无需插件轻松看懂外文网站【方法】
QQ网页版官方账号入口 QQ网页版网页版登录指南
护手霜蹭到袖口上了如何清洗? 怎样避免留下一圈油印?
Python getattr() 异常处理深度解析:避免程序意外退出
PrimeNG Sidebar背景色自定义指南:CSS覆盖与主题化实践
React Router 嵌套组件中 URL 重定向问题的解决方案
没有大陆身份证/银行卡如何实名微信? 亲测有效的几种方法分享
处理动态列数据:J*a ArrayList的正确初始化与字符累加教程
KFC游戏互动怎么赢取优惠券_KFC线上游戏活动参与与优惠代码赢取教程
QQ邮箱官方网站登录入口_QQ邮箱网页版在线使用
zookeeper 都有哪些功能?
圆通快递查询实时追踪 圆通物流包裹状态快速查看
怎样更改Windows系统的默认安装路径_避免C盘爆满的终极设置【技巧】
192.168.1.1管理中心入口 192.168.1.1路由器网页设置平台
Golang如何优雅处理error_Golang error处理最佳实践总结
聚水潭ERP登录页面入口 聚水潭ERP官网登录界面
《燕云十六声》两周内达九百万玩家!位居畅销榜第五
C++如何操作注册表_Windows平台下C++读写注册表的API函数详解
解决J*aScript中重复选择项的确认对话框显示问题


2025-11-05
浏览次数:次
返回列表
er