portals

178 阅读2分钟

portals

将子组件渲染到父组件以外的地方 | v16 react-dom

在react 组件树中子组件与父组件依旧是父子组件关系;

在DOM树中两个组件没有关系

ReactDOM.createPortal(el,aimDom) el(子组件)|aimDom(目标Dom元素)

简单粗暴的🌰 APP:

<div>
 <div id="parentComponent"><Dialog>父组件<Dialog/></div>
</div>

我们可以看到在react组件树中Dialog为parentComponent组件的一个子组件,但是最后渲染出来的Dom树中Dialog变成了parentComponent组件的兄弟组件


portal作为container组件
createPortal(this.props.children,document.getElementById('root'))
​
子组件Dialog
<Containder><div className="child">dddd</div></Containder>

将Dialog的Dom元素放在Container内,通过createPortal直接将Dom元素渲染到root元素下
>>>>相当于将parentComponent的子组件传送到了root组件下

数据传递、生命周期、时间冒泡仍然存在于react 组件树中

Demo — 弹窗 学以致用

场景: 点击button显示弹窗confirm,其中弹窗position:absolute

方案一:

button、confirm为App的子组件,button设置confirm的显示/隐藏状态

button 需要将状态传给App组件,然后App组件将状态再传给confirm;如果button在更深的组件内的话会消耗数据传递的成本

方案二:

confirm 在button 内

button的样式会影响到confirm

方案三:portal

confirm

  • /portal/ToBody (传送门) >>>>> 将子元素渲染至body元素内

  • /dialog/confirm (组件) >>>>>> 子元素

通过按钮控制isShowConfirm展示弹窗,使用ToBody将浮窗渲染作为body子元素

<div className="confirm-btn">
  <button onClick={confirm}>确定</button>
  {isShowConfirm ?
    <ToBody>
       <Confirm
         title="点击确定"
         confirmText="我真的点了"
         cancelText="不,我没点"
         msg="确认您真的点击确定了吗?"
         onConfirm={onConfirm}
         onCancel={onCancel}/>
    </ToBody> : null}
</div>

更多场景: 父组件有overflow、z-index属性,需要跳出父组件的状况