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是不可写的?

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