Portals
某些情况下,我们希望渲染的内容独立于父组件,甚至独立于当前挂载到的DOM元素(默认都是挂载到id为root的DOM元素中)
通常情况下,子元素会被挂载到DOM节点中离其最近的父节点下,但是有时需要将子元素插入到父节点之外的其他地方
Portal提供了一种将子节点渲染到父组件以外的DOM节点的方法:
- 第一个参数(child)是任何可渲染的React子元素,例如:一个子元素、字符串、fragment
- 第二个参数(container)是一个DOM元素
ReactDOM.createPortal(child, container)
Modal组件:
- 在index.html中添加一个新的节点
<div id="modal"></div> - 编写组件代码
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
- 可以看到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
可以看到没有生成额外的包裹元素