开门见山
React的Portal是作甚的?
很简单,当你想把父组件的某个子组件渲染到页面中其它盒子(非父组件子树)里的时候,就用 portal
举个例子
现在有两个组件,Dog和Cat,我们想让Dog的子组件Puppy放到Cat里,当欺负Puppy的时候,即使相隔千里Dog也能感受到。怎么做?用portal!
代码实现
先获取页面中Dog窝和Cat窝
const dogRoot = document.getElementById("dog-house");
const catRoot = document.getElementById("cat-house");
创建一个Puppy组件
class Puppy extends React.Component {
constructor(props) {
super(props);
// 创建一个容器标签
this.el = document.createElement("div");
}
componentDidMount() {
// 把容器标签挂到 catRoot DOM下
catRoot.append(this.el);
}
componentWillUnmount() {
catRoot.removeChild(this.el);
}
render() {
// 利用portal把Puppy的内容放到容器里
return ReactDOM.createPortal(this.props.children, this.el);
}
}
创建Dog组件
class Dog extends React.Component {
constructor(props) {
super(props);
this.state = { bark: 0 };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// 点击的时候 bark + 1
this.setState((state) => ({
bark: state.bark + 1,
}));
}
render() {
// 看上去Puppy组件是在Dog挂在Dog组件里,但其实它被挂载在其它地方
return (
<div onClick={this.handleClick}>
<p>The number of times a big dog barks: {this.state.bark}</p>
<h3>Dog: </h3>
<p>I can't see my children, but I can feel them</p>
<Puppy>
<Bully target={'Puppy'}/>
</Puppy>
<Bully target={'Dog'}/>
</div>
);
}
}
ReactDOM.render(<Dog />, dogRoot);
再创建一个代替欺负Puppy的按钮组件
function Bully(props) {
return (
<>
<button>Bully the {props.target}</button>
</>
);
}
页面效果
接下来看看页面效果:
如图,Dog和猫舍离得很远,它们中间隔了一个世界。
(Dog分属两个兄弟DOM元素下)
此时Puppy在猫舍里,Dog看不到它,因为它们之间隔了一个世界。
当我们想欺负Dog的时候(点击Bully the Dog按钮),它会愤怒地叫一声(barks + 1)。
不敢欺负Dog,我们只好来欺负Puppy,可是当我们想欺负Puppy 的时候(点击Bully the Pully按钮),Dog又愤怒地叫了一声(barks + 1)。
这说明什么?
这说明父母的爱能超越世界的距离
这说明Puppy组件的点击事件冒泡到了Dog组件上,虽然看起来Puppy不在Dog的子树里,但是它仍可以对Puppy的点击事件做出了反应。
总结
Portal方法的作用,就是将子组件渲染到非父组件的子树下,同时父组件仍能对子组件做出反应,我们甚至不用做过多的dom处理。
以上只是本人的一点拙见,如果有不足或不当的地方,还请各位大佬留言指正,感谢。