React17 升级 React18后,ReactDOM.render()动态创建antd Modal的替代方案

616 阅读1分钟

首先上附上说明

// React 17 
import React from 'react'; 
import ReactDOM from 'react-dom'; 
import App from './App'; 

const root = document.getElementById('root')!; 
ReactDOM.render(<App />, root); 

// React 18 
import React from 'react'; 
import ReactDOM from 'react-dom/client'; 
import App from './App'; 
const root = document.getElementById('root')!; 
ReactDOM.createRoot(root).render(<App />);

在react18中,使用旧的api,控制台会有警告 image.png

项目中原先有一个方法,是动态生成一个modal,插入到指定div下的 上代码

// 在需要使用的页面中,引入这个方法,就可以动态创建一个modal
const openDynamicModal = (props: any ={}) => {
  const id = "DynamicModal";
  let div = document.getElementById(id);
  if (div) {
    div.parentElement?.removeChild(div);
  }
  div = document.createElement("div");
  div.id = id;
  
  const ref = createRef<any>();
  const $dom:any = createElement(DynamicModal, {
    ref: ref,
    ...props,
  });
  document.getElementById("root")?.appendChild(div);
  ReactDOM.render($dom,div)
  ref.current.openModal()
};
export default openDynamicModal;

// modal 组件
const DynamicModal = forwardRef((props:any, ref) => {
  const [visible, setVisible] = useState(false);
  useEffect(()=>{
    console.log(props)
  },[])
  
  useImperativeHandle(ref,()=>({
    openModal
  }))
  const onOk = () => {
    setVisible(false);
    props.submit(props.a+props.b)
  };
  const onCancel = () => {
    setVisible(false);
  };
  const openModal = () => {
    setVisible(true)
  }
  return (
    <Modal
      title="Basic Modal"
      centered
      destroyOnClose
      mask
      maskClosable={false}
      visible={visible}
      onCancel={onCancel}
      onOk={onOk}
      afterClose={()=>{
        let div = document.getElementById('DynamicModal')
        div?.parentElement?.removeChild(div)
      }}
      getContainer={document.getElementById('DynamicModal')!}
    >
      <p>Some contents...</p>
      <p>Some contents...</p>
      <p>Some contents...</p>
    </Modal>
  );
});

// 在需要的页面中使用
function App() {
  const submit = (res:any) => {
    console.log(res)
  }
  const openModal = ()=>{
    openDynamicModal({a:1,b:2,submit:submit})
  }
  return (
    <div className="dynamic-modal-test">
      <Button type="primary" onClick={openModal}>召唤动态生成的form</Button>
    </div>
  );
}

export default App;

点击button 召唤modal,会在页面中新增dom

image.png

但是升级react18 后会有报错,就看着很不爽 直接上解决方案

// 修改方法
const openDynamicModal = (props: any ={}) => {
  //...参考上述代码
  document.getElementById("root")?.appendChild(div);
  const modalDiv = ReactDOM.createRoot(document.getElementById('DynamicModal')!);  
  modalDiv.render($dom);
  
  // React 17 ,将这两行代码注释
  // ReactDOM.render($dom,div)
  // ref.current.openModal()
};
export default openDynamicModal;

// 在modal组件中使用useEffect 打开弹窗
const DynamicModal = forwardRef((props:any, ref) => {
  // useEffect中直接调用openModal
  useEffect(()=>{
    console.log(props)
    openModal()
  },[])
})

完美解决,不报错了,暂时不考虑性能问题

image.png