Ant-Design modal对话框未打开时,无法通过uesRef获取modal内部元素DOM节点
为什么要记录下来呢?因为我在网上和chatGpt上没有搜到合适的解决方案。在CDNS上看到个和我遇到问题一样的,居然要收费才能看,所以自己记下来。当然肯定还有其他的好方案,欢迎大家留言。
需求:使用antdV/g6画关系图,类似于企查查上面的那样:点击按钮 打开Modal框,把数据渲染到 Modal框的div上。

遇到的问题:打开Modal时,图渲染不上去,打印ref.current是null,关闭Modal框后,打印的ref.current是 div元素
**以下是父组件代码: 结构图按钮实际是在表格行内的,这里只是模拟**
import React, { useEffect, useState } from 'react';
import { message } from 'antd';
import { StructureGraph } from '@/components/GlobalComponents';
const [imgVisible, setImgVisible] = useState(false); // 结构图弹窗
const [curClickRowData, setCurClickRowData] = useState({}); // 点击的当前行数据
const [imgData, imgLoading, onRequestImg] = useServiceApi(qryProductStructureGraph);
export const ProductInvestmentStatement = () => {
// 点击结构图按钮
const handleClickStructure = (record:any) => {
setCurClickRowData(record);
onRequestImg({
productId: record.productId,
}).then((res) => {
if (res?.tradeNode?.tradeNodeVo) {
setImgVisible(true);
} else {
message.error('此项目还没有结构图!');
}
});
};
return <>
<div onClick={handleClickStructure}>结构图</div>
<StructureGraph
structureData={imgData?.tradeNode || {}}
loading={imgLoading}
id={curClickRowData.productId}
name={curClickRowData.displayShortName}
visible={imgVisible}
onCancel={() => setImgVisible(false)}
/>
</>
}
接下来是子组件代码,已去掉图相关的代码
import React, { useEffect, useRef, useMemo, useState } from 'react';
import { ConfirmModal } from '@/components/GlobalComponents'; // 其实就是antd的Modal框封装了一下样式
export const StructureGraph = ({ structureData, id, visible, onCancel, name }) => {
// 这里使用自定义hook对接口数据做相关的处理
const data = useMemo(() => traverse(structureData, id), [structureData]);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!data || !Object.keys(data).length) return;
if (ref?.current) {
console.log(ref?.current, '3333333333');
}
}, [data, visible]);
return (<ConfirmModal
modalWidth="1140px"
visible={visible}
title={`${name} 结构图`}
cancelText="关闭"
onCancel={onCancel}
noOkBtn
>
<div style={{ width: '100%', height: 500, userSelect: 'none' }} ref={ref} />
</ConfirmModal>);
}


由以上可以看到,Modal框没有渲染在DOM上,但是你的组件其实已经渲染了,这种情况是拿不到 div的ref的。
第一种解决方案: visible为false时,整个组件return null; 但是这样Modal框关闭的动效就没有了,UI应该不能接受。
import React, { useEffect, useRef, useMemo, useState } from 'react';
import { ConfirmModal } from '@/components/GlobalComponents'; // 其实就是antd的Modal框封装了一下样式
export const StructureGraph = ({ structureData, id, visible, onCancel, name }) => {
// 这里使用自定义hook对接口数据做相关的处理
const data = useMemo(() => traverse(structureData, id), [structureData]);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!data || !Object.keys(data).length) return;
if (ref?.current) {
console.log(ref?.current, '3333333333');
}
}, [data, visible]);
// 加上这个就可以了。 但是这样Modal框关闭的动效就没有了
if (!visible) {
return null; // 不渲染 Modal
}
return (<ConfirmModal
modalWidth="1140px"
visible={visible}
title={`${name} 结构图`}
cancelText="关闭"
onCancel={onCancel}
noOkBtn
>
<div style={{ width: '100%', height: 500, userSelect: 'none' }} ref={ref} />
</ConfirmModal>);
}
第二种解决方案: 使用useState新建个newRef,监听这个元素 Modal框动效正常
export const StructureGraph = ({ structureData, id, visible, onCancel, name }) => {
// 这里使用自定义hook对接口数据做相关的处理
const data = useMemo(() => traverse(structureData, id), [structureData]);
const ref = useRef<HTMLDivElement>(null);
const [newRef, setNewRef] = useState(ref); // 通过多创建一个ref,来解决 Modal框未渲染时,拿不到div的问题
useEffect(() => {
if (!data || !Object.keys(data).length) return;
if (ref?.current) {
console.log(ref?.current, '3333333333');
}
}, [data, newRef]); //这里监听newRef
useEffect(() => {
if (visible) {
setNewRef(ref);
} else {
setNewRef(null);
}
}, [visible]);
return (<ConfirmModal
modalWidth="1140px"
visible={visible}
title={`${name} 结构图`}
cancelText="关闭"
onCancel={onCancel}
noOkBtn
>
<div style={{ width: '100%', height: 500, userSelect: 'none' }} ref={ref} />
</ConfirmModal>);
}
最后上图:

浙公网安备 33010602011771号