你能分解懒加载的React组件吗?

25

使用ES6的imports,您可以这样做:

import { MyComponent } from "../path/to/components.js";

export default function () {
  return <MyComponent/>;
}

我能用React.lazy实现同样的效果吗?

const { MyComponent } = lazy(() => import("../path/to/components.js"));

我遇到了以下错误,但我不确定它是否与此相关或其他错误有关:

元素类型无效:预期是字符串(对于内置组件)或类/函数(对于复合组件),但却是:未定义

7个回答

33

当我在使用FontAwesome时遇到这个问题,我是这样解决的:

const FontAwesomeIcon = React.lazy(()=> import('@fortawesome/react-fontawesome').then(module=>({default:module.FontAwesomeIcon})))

18

如果您使用react-lazily,您就可以实现。

import { lazily } from 'react-lazily';
const { MyComponent } = lazily(() => import("../path/to/components.js"));

同时还可以导入多个组件:

const { MyComponent, MyOtherComponent, SomeOtherComponent } = lazily(
  () => import("../path/to/components.js")
);

查看此答案了解更多选项。


这是一个非常棒的库,非常感谢。我能直接将惰性应用于第三方npm包吗? - emre-ozgun
我可以直接将“懒加载”应用于第三方npm包吗? - emre-ozgun
1
@emre-ozgun,我不确定这是否会提供最佳的捆绑大小,因此请确保测试一下,如果从包中添加一个单独的文件来重新导出该组件,是否能更好地进行树摇。 - JLarky

6
当然可以。这是许多人犯过的诚实错误。
const sub = 'a'
const obj = { a: 'alpha', b: 'beta' }

obj.sub // wrong (accessing a direct key)
obj[sub] // right (computed property)

许多人都会犯同样的错误。这还是一个正在进行中的工作,但它表现得非常出色,感谢所有其他回答,让我可以根据自己的需求进行定制。

const ComponentFactory = ({ componentName, ...props }) => {
  const Component = lazy(() => import('baseui/typography').then((module) => ({ default: module[componentName] })))

  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Component {...props} />
    </Suspense>
  )
}

用法:

    <ComponentFactory
      componentName='Paragraph1'
      margin='0.1rem 0rem 0.25rem 0.3rem'
      color={style[of].headingText}
    >
      {headingMessage}
    </ComponentFactory>

4

React.lazy 目前仅支持默认导出。如果您要导入的模块使用命名导出,则可以创建一个中间模块将其重新导出为默认值。这确保了Tree Shaking继续工作,以避免引用未使用的组件。

// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;

// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";

// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));

更多信息请参考:https://reactjs.org/docs/code-splitting.html#named-exports

2

1
我希望你能提供另一种解决方法。该组件将 promise 链接起来,并将具名导出项添加到默认导出项中。src。但是,我不确定这是否会破坏 Tree Shaking。有一些解释在这里
import {lazy} from 'react'
export default (resolver, name = 'default') => {
  return lazy(async () => {
    const resolved = await resolver()
    return {default: resolved[name]}
  })
}


0

您可以通过惰性加载来解决 Promise,并以此方式解决您的命名导出。

语法有点奇怪,但它是有效的:

const MyComponent = React.lazy(
  () =>
    new Promise(async (resolve) => {
      const module = await import('../path/to/components.js');
      resolve({ ...module, default: module.default });
    }),
);


无法工作,错误信息为类型 'typeof import("/media/dimaslanjaka/DATA/Repositories/page/node_modules/rsuite/esm/Nav/index")' 的参数无法分配给类型 '{ default: never; } | PromiseLike<{ default: never; }>'。 - undefined
虽然我不是专家,但也许这与这是一个ESM模块有关?我猜测一下,也许这个线程可能会有用?https://stackoverflow.com/questions/54977743/do-require-resolve-for-es-modules - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接