React函数组件使用AntV G2创建地图报appendChild未定义错误
问题根因
Cannot read properties of undefined (reading 'appendChild') 报错是AntV G2初始化Chart实例时,未找到指定的容器DOM节点导致的,你的代码存在以下几个问题:
- 未从
react包导入useState、useEffect等必须的API,代码里用到的isLoading也没有定义,存在基础语法问题 - 初始化Chart时传入的是字符串ID
container,异步请求返回时可能出现DOM未渲染完成、或同页面多组件ID冲突的问题,无法保证稳定拿到容器节点 - Chart实例所有配置完成后没有调用
chart.render()方法,不会触发视图渲染 - 没有处理组件卸载时销毁Chart实例的逻辑,容易出现内存泄漏
修复方案
按照以下步骤修改代码即可:
- 补全React依赖导入,新增
useRef绑定容器DOM节点,替代字符串ID选择器 - 调整Chart初始化逻辑,先判断容器DOM存在再创建实例,直接传入DOM对象作为container参数
- 配置完Chart后补上
render()调用 - 新增组件卸载时销毁Chart的清理逻辑
完整修复后代码
import React, { useState, useEffect, useRef } from 'react'; import DataSet from '@antv/data-set'; import { Chart } from '@antv/g2'; // 这里替换为你实际的Spinner组件导入路径 import Spinner from './Spinner'; const CustomerByRegion = () => { const [isLoading, setIsLoading] = useState(true); const chartRef = useRef(null); const containerRef = useRef(null); useEffect(() => { getChartData(); // 组件卸载时销毁Chart实例,避免内存泄漏 return () => { if (chartRef.current) { chartRef.current.destroy(); chartRef.current = null; } } } ,[] ); const getChartData = () => { setIsLoading(true); return fetch("https://gw.alipayobjects.com/os/antvdemo/assets/data/world.geo.json") .then(res => res.json()) .then(mapData => { // 容器不存在则终止初始化 if (!containerRef.current) return; // 销毁已存在的实例避免重复渲染 if (chartRef.current) { chartRef.current.destroy(); } const chart = new Chart({ container: containerRef.current, // 直接传入DOM对象作为容器 autoFit: true, height: 500, padding: [55, 20] }); chartRef.current = chart; chart.tooltip({ showTitle: false, showMarkers: false, shared: true, }); chart.scale({ longitude: { sync: true }, latitude: { sync: true } }); chart.axis(false); chart.legend('trend', { position: 'left' }); const ds = new DataSet(); const worldMap = ds.createView('back') .source(mapData, { type: 'GeoJSON' }); const worldMapView = chart.createView(); worldMapView.data(worldMap.rows); worldMapView.tooltip(false); worldMapView.polygon().position('longitude*latitude').style({ fill: '#fff', stroke: '#ccc', lineWidth: 1 }); // 触发图表渲染 chart.render(); }) .finally(() => { setIsLoading(false); }) } return isLoading ? ( <Spinner /> ) : ( <div ref={containerRef} style={{width: '100%'}}></div> ); }; export default CustomerByRegion;
内容的提问来源于stack exchange,提问作者Mani
相关产品推荐
相关产品推荐

