美文网首页
Portals 传送门

Portals 传送门

作者: 豆豆猫1031 | 来源:发表于2018-02-23 11:52 被阅读0次

React Portal之所以叫Portal,因为做的就是和“传送门”一样的事情:render到一个组件里面去,实际改变的是网页上另一处的DOM结构。
实际上解决的痛点:一个组件的交互涉及到一个非父类组件 这时候要么用全局状态管理传数据 要么通过"传送门"直接推一个子组件过去

传送门 v16之前的实现:
基于API:
unstable_renderSubtreeIntoContainer
unmountComponentAtNode

import React from 'react';
import {unstable_renderSubtreeIntoContainer, unmountComponentAtNode}
from 'react-dom';

class Dialog extends React.Component {
render() {
return null;
}

componentDidMount() {
const doc = window.document;
this.node = doc.createElement('div');
doc.body.appendChild(this.node);

this.renderPortal(this.props);

}

componentDidUpdate() {
this.renderPortal(this.props);
}

componentWillUnmount() {
unmountComponentAtNode(this.node);
window.document.body.removeChild(this.node);
}

renderPortal(props) {
unstable_renderSubtreeIntoContainer(
this, //代表当前组件
<div class="dialog">
{props.children}
</div>, // 塞进传送门的JSX
this.node // 传送门另一端的DOM node
);
}
}

总结:
它什么都不给自己画,render返回一个null就够了;
它做得事情是通过调用renderPortal把要画的东西画在DOM树上另一个角落。

传送门 v16的实现:
在v16中,使用Portal创建Dialog组件简单多了,不需要牵扯到componentDidMount、componentDidUpdate,也不用调用API清理Portal,关键代码在render中,像下面这样就行。(脏活render()都干了)

import React from 'react';
import {createPortal} from 'react-dom';

class Dialog extends React.Component {
constructor() {
super(...arguments);
const doc = window.document;
this.node = doc.createElement('div');
doc.body.appendChild(this.node);
}

render() {
return createPortal(
<div class="dialog">
{this.props.children}
</div>, //塞进传送门的JSX
this.node //传送门的另一端DOM node
);
}

componentWillUnmount() {
window.document.body.removeChild(this.node);
}
}

3.1官方的v16传送门实现
// These two containers are siblings in the DOM
const appRoot = document.getElementById('app-root');
const modalRoot = document.getElementById('modal-root');

// Let's create a Modal component that is an abstraction around
// the portal API.
class Modal extends React.Component {
constructor(props) {
super(props);
// Create a div that we'll render the modal into. Because each
// Modal component has its own element, we can render multiple
// modal components into the modal container.
this.el = document.createElement('div');
}

componentDidMount() {
// Append the element into the DOM on mount. We'll render
// into the modal container element (see the HTML tab).
modalRoot.appendChild(this.el);
}

componentWillUnmount() {
// Remove the element from the DOM when we unmount
modalRoot.removeChild(this.el);
}

render() {
// Use a portal to render the children into the element
return ReactDOM.createPortal(
// Any valid React child: JSX, strings, arrays, etc.
this.props.children,
// A DOM element
this.el,
);
}
}

  1. v16之前传送出去的组件不冒泡回来了(应该是在传送出去的那一端冒泡 有待考证) v16之后传送出去的组件事件会冒泡回来
    // These two containers are siblings in the DOM
    const appRoot = document.getElementById('app-root');
    const modalRoot = document.getElementById('modal-root');

class Modal extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
}

componentDidMount() {
modalRoot.appendChild(this.el);
}

componentWillUnmount() {
modalRoot.removeChild(this.el);
}

render() {
return ReactDOM.createPortal(
this.props.children,
this.el,
);
}
}

class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {clicks: 0};
this.handleClick = this.handleClick.bind(this);
}

handleClick() {
// This will fire when the button in Child is clicked,
// updating Parent's state, even though button
// is not direct descendant in the DOM.
this.setState(prevState => ({
clicks: prevState.clicks + 1
}));
}

render() {
return (
<div onClick={this.handleClick}>
<p>Number of clicks: {this.state.clicks}</p>
<p>
Open up the browser DevTools
to observe that the button
is not a child of the div
with the onClick handler.
</p>
<Modal>
<Child />
</Modal>
</div>
);
}
}

function Child() {
// The click event on this button will bubble up to parent,
// because there is no 'onClick' attribute defined
return (
<div className="modal">
<button>Click</button>
</div>
);
}

ReactDOM.render(<Parent />, appRoot);

相关文章

  • Portals 传送门

    React Portal之所以叫Portal,因为做的就是和“传送门”一样的事情:render到一个组件里面去,实...

  • 进击的 react Protals组件使用

    Portals是什么?用来干啥?。翻译过来 就是“传送门”,是React 16版本中新加的组件功能。使用场景:当父...

  • React 的类似 vue slot 插槽的 功能 api

    Portals API: https://reactjs.org/docs/portals.html[https:...

  • 02-react-传送门Portals的简介和使用

    Portals Portal[https://zh-hans.reactjs.org/docs/portals.h...

  • Unity 密闭空间动态可控性渲染(Occlusion Port

    Occlusion Portals Occlusion Portals组件用来实现Camera对于密闭空间的动态可...

  • Portals

    将子节点渲染到存在于父组件以外的dom节点的方案 1 .对话卡,悬浮卡,提示框2 .为什么可以这么简单。。。感觉用...

  • Portals

    Portals React 16的Portals特性让我们可以把组件渲染到当前组件树以外的 DOM节点上,这个特性...

  • # Portals

    插槽:将一个react元素渲染到指定的DOM容器中 ReactDOM.createPortal(React 元素,...

  • React Portals

    Protals用法: ReactDOM.createPortal(child, container) 看了官方文档...

  • Portals使用

    某些情况下,我们希望渲染的内容独立于父组件,甚至是独立于当前挂载到的DOM元素中(默认都是挂载到id为root的D...

网友评论

      本文标题:Portals 传送门

      本文链接:https://www.haomeiwen.com/subject/vwztxftx.html