react-portal/懒加载

loading 2022年12月15日 94次浏览

1. portal

portal提供了一个最好的在父组件包含的DOM结构层级外的DOM节点渲染组件的方法,比如遮罩层

举个例子,现在有一个父div里包着左div和右div,希望点击右div中的按钮能实现把两个div都遮罩起来,如果是常规创建右div会因为父组件的DOM元素有着overflow:hidden或者z-index等样式不那么好实现,因此可以采用portal的创建方法:

可以看到return了一个createProtal包装起来的div,第二个参数设置为document.body,意为此组件创建的容器。

export default class Dialog extends Component {
    render() {
        return createPortal(
            <div style={{ width: '100%', height: '100%', position: 'fixed', left: 0, top: 0, background: 'rgba(0,0,0,0.7)', zIndex: "9999999" }}>
                <button onClick={this.props.onCloseTheLayer}>close</button>
            </div>,
            document.body
        )
    }
}

这是父组件

export default class App extends Component {
    state = {
        isShow: false
    }
    render() {
        return (
            <div className="box">
                <div className="left"></div>
                
                <div className="right">
                    <button onClick={() => {
                        this.setState({
                            isShow: true
                        })
                    }}>ajax</button>
                    {
                        this.state.isShow && <Dialog onCloseTheLayer={() =>{
                            this.setState({
                                isShow: false
                            })
                        }}></Dialog>
                    }
                </div>
            </div>
        )
    }
}

虽然通过portal渲染的元素在父组件的盒子之外,但是渲染的dom节点仍在React的元素树上,在那个dom元素上的点击事件仍然能在dom树中监听到。

具体原因可以看react事件的那篇博客,react所有事件统一挂载在根节点上管理

2. 懒加载

通过React.lazy函数实现动态引入组件,也即懒加载。

当程序越来越大,代码量越来越多。一个页面上堆积了很多功能,也许有些功能很可能都用不到,但是一样下载加载到页面上,所以这些加载可以被优化。

该函数原理是当Webpack解析到该语法时,它会自动地开始进行代码分割(Code Splitting),分割成一个文件,当使用到这个文件的时候会这段代码才会被异步加载。

在React.lazy和常用的三方包react-loadable,都是使用了这个原理,然后配合webpack进行代码打包拆分达到异步加载,这样首屏渲染的速度将大大的提高。
由于React.lazy不支持服务端渲染,所以这时候react-loadable就是不错的选择。

具体用法:

  • 导入组件时使用React.lazy()
  • 通过Suspense包装起需要懒加载的组件,并且在fallback参数中提供加载时要展示的内容/组件
const Nowplaying = React.lazy(() => import('./components/Nowplaying'))
const Comingsoon = React.lazy(() => import('./components/Comingsoon'))

export default class App extends Component {
    state = {
        type: 1
    }
    render() {
        return (
            <div>
                <button onClick={() => {
                    this.setState({
                        type: 1
                    })
                }}>正在热映</button>
                <button onClick={() => {
                    this.setState({
                        type: 2
                    })
                }}>即将上映</button>

                <Suspense fallback={<div>正在加载中....</div>}>
                    {
                        this.state.type === 1 ?
                            <Nowplaying></Nowplaying>
                            :
                            <Comingsoon></Comingsoon>
                    }
                </Suspense>

            </div>
        )
    }
}