React16的一些特性:
- Fragment
- Portals
- lazy,Suspense
Fragment
根节点用div会导致DOM里多出不少额外的div,可以用React.Fragment代替。当然最主要的原因是:有时候组件需要返回多个元素,根节点不能是div。例如表格td组件:
class Columns extends React.Component { render() { // 根节点如果是div,将无法使用,因为tr里里没有div return ( <React.Fragment> <td>Hello</td> <td>World</td> </React.Fragment> ); } }
React.Fragment支持空标签的简写形式,当然你要确认一下IDE支不支持这样的写法。
<> <td>Hello</td> <td>World</td> </>
Portals
正常情况下,组件的render方法返回的元素会被装载到最近父节点DOM中,如果想将它装载到其他DOM节点中,可以用插槽。常被用于Modal,hover等,能让元素在父组件有 overflow: hidden或z-index样式的情况下,产生一种跳出容器的感觉。
在React15里,可以用unstable_renderSubtreeIntoContainer不稳定的API,实现插槽:
ReactDom.unstable_renderSubtreeIntoContainer( parentComponent component, domContainer, callback, );
React16里,可以用ReactDOM.createPortal(child, container)来创建插槽,参数child是React子组件,参数container是任何有效的DOM节点。
尽管插槽可以让React子节点安置在DOM树的任何地方,但其他方面其行为和普通的React子节点行为一致,仍存在于React tree中,不用考虑其在DOM tree中的位置。
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; const modalRoot = document.getElementById('root'); class Modal extends Component { constructor(props) { super(props); this.el = document.createElement('div'); } componentDidMount() { modalRoot.appendChild(this.el); } componentWillUnmount() { modalRoot.removeChild(this.el); } render() { return ReactDOM.createPortal( this.props.children, this.el, ); } } export default class Parent extends Component { constructor(props) { super(props); this.state = { clicks: 0 }; } handleClick = () => { this.setState(state => ({ clicks: state.clicks + 1 })); }; render() { return ( <div onClick={this.handleClick}> <p>点击次数: {this.state.clicks}</p> <p>打开调试面板,button不在该div内</p> <Modal> <div className="modal"> <button>点击</button> </div> </Modal> </div> ); } }
lazy,Suspense
React.lazy可以支持动态加载组件,要和React.Suspense配合使用,否则会报错,而且还不可用于服务器端渲染。如果要在服务器渲染中进行代码拆分,建议使用Loadable。
import React, { Component, lazy, Suspense } from 'react'; import ErrorBoundary from './ErrorBoundary'; const OtherComponent = lazy(() => import('./OtherComponent')); export default class MyComponent extends Component { render() { return ( <div> <ErrorBoundary> <Suspense fallback={ <div>Loading...</div> }> <OtherComponent /> </Suspense> </ErrorBoundary> </div> ); } }
React.lazy接受一个函数,必须调用动态import(),返回Promise,resolves一个带有包含default导出模块的React组件。
React.Suspense组件的fallback属性接受在等待时渲染的React组件。React.Suspense可以放在要懒加载组件上方的任何位置。