08_Portals和Fragment

166 阅读1分钟

Portals

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

通常情况下,子元素会被挂载到DOM节点中离其最近的父节点下,但是有时需要将子元素插入到父节点之外的其他地方

Portal提供了一种将子节点渲染到父组件以外的DOM节点的方法:

  • 第一个参数(child)是任何可渲染的React子元素,例如:一个子元素、字符串、fragment
  • 第二个参数(container)是一个DOM元素

ReactDOM.createPortal(child, container)

Modal组件:

  1. 在index.html中添加一个新的节点<div id="modal"></div>
  2. 编写组件代码
import React, { PureComponent } from 'react'
import { createPortal } from "react-dom"

class Modal extends PureComponent {
  render() {
    return createPortal(this.props.children, document.querySelector("#modal"))
  }
}

class App extends PureComponent {
  render() {
    return (
      <div className='app'>
        <h1>App</h1>
        
        <Modal>
          <h2>我是标题</h2>
          <p>我是内容, 哈哈哈</p>
        </Modal>
      </div>
    )
  }
}

export default App
  1. 可以看到Modal组件的子元素挂载到了id为modal的元素下

Fragment

之前总在一个组件返回内容时包裹一个div元素,但是这个div可能没有什么实际作用,仅仅是为了有一个根节点

<Fragment>组件通常使用 <>...</> 代替,它们都允许你在不添加额外节点的情况下将子元素组合。

注意:需要给Fragment添加key属性时,不能使用 <>...</> ,必须从React导入Fragment使用

import React, { PureComponent, Fragment } from 'react'

export class App extends PureComponent {
  constructor() {
    super() 

    this.state = {
      sections: [
        { title: "周杰伦", content: "我是周杰伦" },
        { title: "林俊杰", content: "我是林俊杰" },
        { title: "陶喆", content: "我是陶喆" },
        { title: "王力宏", content: "我是王力宏" },
      ]
    }
  }

  render() {
    const { sections } = this.state

    return (
      <>
        <h2>我是App的标题</h2>
        <p>我是App的内容, 哈哈哈哈</p>
        <hr />

        {
          sections.map(item => {
            return (
              <Fragment key={item.title}>
                <h2>{item.title}</h2>
                <p>{item.content}</p>
              </Fragment>
            )
          })
        }
      </>
    )
  }
}


export default App

可以看到没有生成额外的包裹元素