为什么要记录下来呢?因为我在网上和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>); }
最后上图:
标签:const,modal,DOM,data,对话框,visible,Modal,return,ref From: https://www.cnblogs.com/zpy521hl/p/17865468.html