1. 程式人生 > >React 16.0中的新特性——portal及其注意點

React 16.0中的新特性——portal及其注意點

簡要介紹:React16.0中釋出了很多新特性,我們來看portal,React提供了一個頂級API—portal,用來將子節點渲染到父節點之外的dom節點

1.基本用法

(1)在React15.X版本中,我們只能講子節點在父節點中渲染,基本用法如下:

render() {
  // React需要建立一個新的div來包含子節點
  return (
    <div>
      {this.props.children}
    </div>
  );
}

但是如果需要將子節點插入到父節點之外的dom呢,React15.x及之前都沒有提供這個功能的API。

(2)React16.0中的portal

render() {
  // React不需要建立一個新的div去包含子元素,直接將子元素渲染到另一個
  //dom節點中
  //這個dom節點可以是任何有效的dom節點,無論其所處於dom樹中的哪個位置 

  return ReactDOM.createPortal(
    this.props.children,
    domNode,
  );
}
  1. Portal中的dom節點必須是有效的節點

ReactDOM.createPortal函式的第二個引數,是被插入的dom節點,並且這個dom節點是有效的節點,而不能是通過ref獲得並傳遞的virtual dom節點,舉例來說:

class MyTestableClass extends React.Component{
    constructor(){
      super();
      this.state={
        sprop:''
      }
    }
    render(){
      return <div>
              <Left ref={(input)=>{this.left=input}}>我是左邊的資訊</Left>
              <Right sprop={this.state.sprop}>我是右邊的資訊</Right>
      </div
> } componentDidMount(){ var left=this.left; var state=this.state; this.setState({ sprop:left }) } } ReactDom.render( <MyTestableClass/>,document.getElementById('app') )

在整個元件中,我們將ref獲得的子節點Left,通過props傳遞給了子節點Right,然後在Right子節點中,通過:

class Right extends React.Component{
   constructor(){
     super();
   }
   render(){
     var props=this.props;
     if(this.props.sprop){
       return <div className="right">{this.props.children}</div>
     }else{
       return ReactDOM.createPortal(
            this.props.children,
            this.props.sprop
             );
     }

   }
  componentWillReceiveProps(nextProp){
    console.log(nextProp.sprop);
  }
}

我們嘗試將子節點插入到通過props傳遞過來的另一個節點this.props.sprop中,因為this.props.sprop並不是一個valid dom node,它是一個virtual dom node,因此會報錯:

//Target container is not a DOM element.

3.通過Portals實現事件冒泡

雖然一個portal可以插入到任何一個存在dom樹中,但是通過Portal節點插入到其他dom中的節點,跟其他的React普通的子節點表現相同。在父節點下,通過Portal插入的子節點也可以共享context。

對於事件冒泡,從Portal節點中觸發的事件,雖然可能改變了節點所處的位置,但是在HTML結構中的父包含節點是可以拿到這個事件的。

<html>
  <body>
    <div id="app-root"></div>
    <div id="modal-root"></div>
  </body>
</html>

在上面的HTML結構中,通過Portal, 在Button真實位置是包含在“modal-root”下,但是因為在HTML的結構中Button所在的父節點的HTML結構是包含“app-root”中的,因此在“modal-root”中出發的事件,也可以冒泡到“app-root”中。