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就實現了性能

相關文章
相關標籤/搜索