ReactLazy的自定义实现

React v16.6 版本引入了React.lazy,Suspense的功能,这个功能主要是利用了webpack对于es6的import动态载入组件,能够实现组件的懒加载,react路由的按需加载之类的功能react

先演示下React Lazy的简单实用webpack

// App.js

import React, { lazy, Suspense } from 'react';
const Child = lazy(() => import('./Child'))

function App() {
	return (
		<div className="App">
			<Suspense fallback={<div>Loading...</div>}>
				<Child />
			</Suspense>
		</div>
	);
}

export default App;

复制代码
// Child.js

import React from 'react';

class Child extends React.Component{
    render(){
        return <div class="childClass">我是子组件啊</div>
    }
}

export default Child;
复制代码

这是最简单的一个lazy demo,过多的不讲了,能够参考React性能优化之代码分割es6

启动项目以后能够发现Child.js已经被打包到2.chunk.js了web

从 Lazy demo 能够总结几个点性能优化

  • React Lazy须要配合Suspense使用,Suspense提供了fallback,为Lazy作优雅降级
  • 熟悉React高阶函数的话,lazy函数是个相似属性代理的高阶函数,参数是一个thenable的对象,能够取到WrappedComponent

抓住这两个重点,能够用属性代理的高阶组件来实现下bash

// App.js

import React from 'react';
import MyLazy from './MyLazy';
import MySuspense from './MySuspense';

const Child = MyLazy(() => import('./Child'))

function App() {
	return (
		<div className="App">
			<MySuspense fallback={<div>Loading...</div>}>
				<Child />
			</MySuspense>
		</div>
	);
}

export default App;

复制代码
// MySuspense.js

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

class MySuspense extends PureComponent{
    getChildContext(){
        return {
            fallback: this.props.fallback
        }
    }

    render(){
        return this.props.children;
    }
}

MySuspense.childContextTypes = {
    fallback: PropTypes.element
};

export default MySuspense;
复制代码
// MyLazy.js

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

export default load => {
    class MyLazy extends PureComponent{
        constructor(){
            super();

            this.state = {
                WrappedComponent: null
            };
        }

        componentDidMount(){
            load().then(({ default: Comp })  => {
                setTimeout(() => {
                    this.setState({
                        WrappedComponent: Comp
                    });
                }, 3000);
            })
        }

        render(){
            const { WrappedComponent } = this.state;

            return WrappedComponent ? <WrappedComponent /> : this.context.fallback
        }
    }

    MyLazy.contextTypes = {
        fallback: PropTypes.element
    };

    return MyLazy;
}
复制代码
// Child.js

import React from 'react';

class Child extends React.Component{
    render(){
        return <div>i am child</div>
    }
}

export default Child;
复制代码

MyLazy就是个属性代理的高阶组件,可是有个两个问题是app

  • 如何用fallback来作优雅降级啊
  • 如何获取MySuspense里props的fallback

从官网的Suspense解释来看,能够发现Lazy其实能够放在Suspense下children的任何解构,就是说Suspense和Lazy之间的层级是不固定的,那么使用props来传输fallback有点不现实,没有去看过官方源码,因此我采用的是虫洞congtext的方式去实现函数

虫洞的具体实现细节,能够参考React性能优化之代码分割post

到这里,一个自定义最简单的Lazy和Suspense就实现了性能

相关文章
相关标签/搜索