简体   繁体   English

React Suspense 延迟加载没有回退

[英]React Suspense lazy loading without fallback

I want to lazy load my components to decrease my initial bundle size and get components on the fly using code splitting using react router.我想延迟加载我的组件以减少我的初始包大小并使用反应路由器使用代码拆分即时获取组件。

However, when using React Suspense, they force you to use a fallback for loading.但是,当使用 React Suspense 时,它​​们会强制您使用后备进行加载。
This wouldn't work:这行不通:

const lazyLoadComponent = Component =>
    props => (
        <Suspense> // Missing fallback property
            <Component {...props} />
        </Suspense>
    );

In my case I am rendering html from the server so I don't want to use a spinner.在我的情况下,我正在从服务器渲染 html,所以我不想使用微调器。
This would create a useless flicker on my screen!这会在我的屏幕上产生无用的闪烁! Ie: IE:

  • Html loads Html 加载
  • Place holder appears占位符出现
  • PageComponent for the route gets loaded路由的 PageComponent 被加载
  • I have my own spinner that loads a feed from within the page component我有自己的微调器,可以从页面组件中加载提要

In my case the html corresponds to the react component that gets loaded.在我的情况下,html 对应于被加载的反应组件。

Is there any known hack to easily work around this problem (except for creating a loader for any route that copies the html (!!), which by the way, would make lazy loading useless).是否有任何已知的黑客可以轻松解决此问题(除了为复制 html(!!)的任何路由创建加载程序,顺便说一下,这会使延迟加载无用)。

I am a bit displeased with "forcing" us to add a loader and I don't understand the logic behind the decision to make it mandatory.我对“强迫”我们添加一个加载器有点不满意,我不理解强制执行的决定背后的逻辑。

Try to use code splitting in the docs尝试在文档中使用代码拆分

fallback props is just a React element, you can set it for null . fallback props 只是一个 React 元素,你可以将它设置为null

const MyLazyComponent= React.lazy(() => import('./MyComponent'));

<Suspense fallback={null}>
    <MyLazyComponent />
</Suspense>

I created an issue for this on Github: https://github.com/facebook/react/issues/19715我在 Github 上为此创建了一个问题: https ://github.com/facebook/react/issues/19715

There isn't a current clean solution using React-Router / React.目前没有使用 React-Router / React 的干净解决方案。
This is however foreseen in a future release using concurrent mode.然而,在使用并发模式的未来版本中可以预见到这一点。 As mentioned by Dan Abramov:正如丹·阿布拉莫夫所说:

Regarding your concrete feature request, I think I can reframe it slightly differently.关于您的具体功能要求,我想我可以稍微改变一下。 It's not that you want "optional fallback" since that wouldn't make sense for new screens (we've got to show something).这并不是说您想要“可选的后备”,因为这对新屏幕没有意义(我们必须展示一些东西)。 What I believe you're looking for is a way to skip showing the fallback if the content is already in HTML.我相信您正在寻找的是一种在内容已经在 HTML 中时跳过显示回退的方法。 This is precisely how React behaves in Concurrent Mode so the feature request is already implemented (and will eventually become the default behavior in a stable release).这正是 React 在并发模式下的行为方式,因此功能请求已经实现(并且最终将成为稳定版本中的默认行为)。

For me it is not a problem to wait, so currently I will omit lazy-loading the routes as this concerns a hobby-project and I have time to wait for a future release.对我来说等待不是问题,所以目前我将省略延迟加载路线,因为这涉及到一个爱好项目,我有时间等待未来的发布。

In my experience (with React 17), there's no flickering happens if you pass null to fallback param.根据我的经验(使用 React 17),如果将 null 传递给后备参数,则不会发生闪烁。

I have a Modal component that renders lazy components.我有一个呈现惰性组件的模态组件。

Here's my Typescript solution:这是我的打字稿解决方案:

type LazyLoadHOC = {
   component: React.LazyExoticComponent<any>,
   fallback?: React.ComponentType | null,
   [x:string]: any
};

export const LazyLoad: React.FC<LazyLoadHOC> = ({
     component: Component, fallback = null, ...props
}) => {
  return (
    <React.Suspense fallback={fallback}>
        <Component {...props} />
    </React.Suspense>
  );
};

Here's my Modal:这是我的模态:

const AddressFormModel = React.lazy(() => import('@components/address/address-form-modal'));

<Modal show={isOpen} backdrop={'static'} dialogClassName='custom-modal'>
    <ModalBody>
       {view === 'ADDRESS-FORM' && <LazyLoad component={AddressFormModel} />}
    </ModalBody>
</Modal>

This will ensure to not trigger your global React.Suspense.这将确保不会触发您的全局 React.Suspense。

So basically all we have to do is, wrap the loader in a component and load the script using that component (Loadable here).所以基本上我们所要做的就是将加载器包装在一个组件中并使用该组件加载脚本(此处为可加载)。 This way we can use React.lazy wihtout any animation.这样我们就可以在没有任何动画的情况下使用 React.lazy。

Since our fallback is empty you wont see any animation and your content will be visible always.由于我们的后备是空的,您将看不到任何动画,并且您的内容将始终可见。 There will not be any flicker of content hiding.内容隐藏不会有任何闪烁。

loadable.js可加载的.js

import React, { Suspense } from 'react';

const Loadable = (Component) => (props) => (
  <Suspense fallback={<></>}>
    <Component {...props} />
  </Suspense>
);

export default Loadable;

We can wrap the import in Loadable so that it will load lazy.我们可以将导入包装在 Loadable 中,以便它可以延迟加载。 route.js路由.js

import React, { lazy } from 'react';
import Loadable from './components/Loadable';

// page import
const Home = Loadable(lazy(() => import('./pages/home')));

// define routes
const routes = [
    {
        path: "dashboard",
        element: <Layout />,
        children: [
            {
                path: "",
                element: <Home />,
            },
        ]
    },
]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM