import按需加載react類組件時引發的bug

問題描述

由於項目工程特別大,使用了import函數與@loadable/component結合進行組件的動態加載,從而實現Code Splitting的效果。

如下是一個測試組件的代碼:

// 這是一個組件
import React from 'react';

interface Props {};

export default class Demo extends React.Component<Props> {
    render () {
        return (
            <div>this is a test component</div>
        );
    }
};

如下是一個組件動態加載的函數:

import loadable from '@loadable/component';

export const lazyLoad = (
    loader: () => Promise<any>,
    componentName?: string,
) => {
    return loadable(
        () => loader().then((module) => {
            if (componentName) {
                module.default = module[componentName];
            }
            return module;
        })
    );
};

如下是進行組件動態加載:

import { lazyLoad } from './lazyLoad';

const DemoComponent = lazyLoad(() => import('./Demo'), 'default')

如此操作之後,理想是豐滿的現實是骨幹的,報錯了,報錯調用棧如下:

lazyLoad報錯信息

問題解決

剛看到問題的時候一臉懵逼,內心wtf呀,這是什麼鬼,什麼造成了這個加載報錯,仔細看這個報錯的調用棧是調用@loadable/componentloadable函數時報錯的。原因是loadable.esm.js:272 Uncaught TypeError: Cannot set property default of #<Object> which has only a getter at lazy-load.tsx:18,仔細看一下是說無法對#<Object>default屬性進行設置,因爲該屬性是隻讀的。這更懵逼了,這是什麼鬼,爲什麼不能對default屬性進行設置呢。看了一下代碼只有在lazyLoad時執行了module.default = module[componentName],難道是這個moduledefault屬性是不可寫的嘛?寫個測試代碼看一下:

// utils.ts
export function DemoFunc () {};

function decorate (obj) {
  obj.displayName = 'DemoClass'
  return obj
}

@decorate
export default class DemoClass {};
// import
import(
    './utils'
)
.then(module => {
    console.log(module);
})

console.log出來的內容:

esModule

同樣的log一下項目裏面的module:

_esModule

同樣的我們都發現了一個問題module上面的default屬性是訪問器屬性是隻讀的,不可進行更改,但是可以對具名組件進行default掛載,也就是說,可以將組件具名導出來,然後在lazyLoad的時進行default掛載。

demo如下:

// utils.ts
export function DemoFunc () {};

function decorate (obj) {
  obj.displayName = 'DemoClass'
  return obj
}

@decorate
export class DemoClass {};

// 動態加載
import(
    './utils'
)
.then(module => {
    module.default = module.DemoClass;
    console.log(module);
})

log如下所示:

import

這個時候我們就看到了,已經成功的爲moduledefault屬性掛礙上具名組件了。

提問

雖然問題解決了,但依然有個疑問,求各位大神留言解答:
1、爲什麼經過裝飾器修飾的類組件,export defaultmodule上只讀,而沒有裝飾器修飾類組件可讀性也可寫?

2、爲什麼import函數動態加載的具名類module是不可寫的?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章