我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

react教程,如何利用传统门功能异位渲染一个组件?在上一篇文章中,已经对传送门的基本原理进行了描述。使用的例子是基于传统的类组件的,在组件加载的时候,添加一个临时容器。在组件卸载的时候,删除这个临时容器。那么,这个时机在函数组件里面说明的话,就是副作用,会使用useEffect进行管理。

苏南大叔:react教程,类/函数两种组件方式使用传统门功能异位渲染 - 传送门功能2
react教程,类/函数两种组件方式使用传统门功能异位渲染(图5-1)

苏南大叔的程序如此灵动博客,记录苏南大叔和计算机代码的故事。测试环境:create-react-app@5.0.1react@18.2.0react-dom@18.2.0node@16.14.2

类组件传送门(前文回顾)

在上一篇文章的第二个例子里面,代码把所有的浮层对话框之类的组件都集中到了一个叫做root-modaldiv里面。这个特殊的div置于body下面。

核心代码:

import React from 'react';
import ReactDOMPortal from 'react-dom';

const root_modal = document.getElementById('root-modal');
class Modal extends React.Component {
  constructor(props) {
    super(props);
    this.el = document.createElement('div');
  }
  componentDidMount() {
    root_modal.appendChild(this.el);
  }
  componentWillUnmount() {
    root_modal.removeChild(this.el);
  }
  render() {
    return ReactDOMPortal.createPortal(
      this.props.children,
      this.el
    );
  }
}

苏南大叔:react教程,类/函数两种组件方式使用传统门功能异位渲染 - 方式一
react教程,类/函数两种组件方式使用传统门功能异位渲染(图5-2)

函数组件传送门【重点】

核心代码:

import React, { useEffect, useRef } from 'react';
import ReactDOMPortal from 'react-dom';

const root_modal = document.getElementById('root-modal');
function Modal2(props) {
  const el_ref = useRef(null);
  if (!el_ref.current) {
    el_ref.current = document.createElement('div');
  }
  useEffect(() => {
    root_modal.appendChild(el_ref.current);
    return () => {
      root_modal.removeChild(el_ref.current);
      el_ref.current = null;
    }
  }, []);
  return ReactDOMPortal.createPortal(
    props.children,
    el_ref.current
  );
}

苏南大叔:react教程,类/函数两种组件方式使用传统门功能异位渲染 - 方式二
react教程,类/函数两种组件方式使用传统门功能异位渲染(图5-3)

完整代码

index.html里面,有两个divreact的容器。

<div id="root"></div>
<div id="root-modal"></div>

苏南大叔:react教程,类/函数两种组件方式使用传统门功能异位渲染 - 传递root
react教程,类/函数两种组件方式使用传统门功能异位渲染(图5-4)

src/index.js【注意props.root字样】:

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

下面的例子,分别使用两种方式创建了react的传送门功能。一个是使用类组件,另外一个是函数组件。两种类型的组件,核心函数都是createPortal()

苏南大叔:react教程,类/函数两种组件方式使用传统门功能异位渲染 - umount
react教程,类/函数两种组件方式使用传统门功能异位渲染(图5-5)

import React, { useEffect, useRef } from 'react';
import ReactDOMPortal from 'react-dom';

const root_modal = document.getElementById('root-modal');
function Modal2(props) {
  const el_ref = useRef(null);
  if (!el_ref.current) {
    el_ref.current = document.createElement('div');
  }
  useEffect(() => {
    root_modal.appendChild(el_ref.current);
    return () => {
      root_modal.removeChild(el_ref.current);
      el_ref.current = null;
    }
  }, []);
  return ReactDOMPortal.createPortal(
    props.children,
    el_ref.current
  );
}
class App extends React.Component {
  constructor(props) {
    super(props);
    this.root = props.root;
    this.state = { clicks: 0 };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    if (this.state.clicks >= 2) {
      this.root.unmount();
    }
    this.setState(state => ({
      clicks: state.clicks + 1
    }));
  }
  render() {
    return (
      <div onClick={this.handleClick}>
        <Modal>
          <Child cnt={this.state.clicks} />1
        </Modal>
        <Modal2>
          <Child cnt={this.state.clicks} />2
        </Modal2>
      </div>
    );
  }
}
function Child(props) {
  return (
    <button>实际脱离文档流了,但是依然响应react事件[{props.cnt}][3次毁灭]</button>
  );
}
export default App;

【重要结论】为了监测卸载的效果,在点击三次之后,使用root.unmount()来卸载reactroot容器。可以看到modal-root容器内的组件也被卸载。(通过WillUnmount()来进行卸载)。

结束语

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react