react悬念/懒惰延迟?

IT技术 javascript reactjs
2021-04-04 09:13:12

我正在尝试使用新的 React Lazy 和 Suspense 创建回退加载组件。这很好用,但回退只显示几毫秒。有没有办法添加额外的延迟或最短时间,以便我可以在渲染下一个组件之前显示来自该组件的动画?

现在懒惰导入

const Home = lazy(() => import("./home"));
const Products = lazy(() => import("./home/products"));

等待组件:

function WaitingComponent(Component) {

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

我可以做这样的事情吗?

const Home = lazy(() => {
  setTimeout(import("./home"), 300);
});
6个回答

lazy函数应该返回一个{ default: ... }对象的Promise,该对象由import()具有默认导出的module返回setTimeout不返回Promise,不能像那样使用。虽然任意Promise可以:

const Home = lazy(() => {
  return new Promise(resolve => {
    setTimeout(() => resolve(import("./home")), 300);
  });
});

如果目标是提供最小延迟,这不是一个好的选择,因为这会导致额外的延迟。

最小延迟为:

const Home = lazy(() => {
  return Promise.all([
    import("./home"),
    new Promise(resolve => setTimeout(resolve, 300))
  ])
  .then(([moduleExports]) => moduleExports);
});
你能解释一下为什么第一个代码不起作用吗?setTimeout 将在 300 密耳后解决Promise。谢谢
2021-05-30 09:13:12
另一种方法可能是使用Promise.all([import(...), delayPromise]),它并行执行导入和延迟,也更容易理解。
2021-05-30 09:13:12
@AdiAzarya 它会工作,但不会按要求工作。延迟将是加载时间加上额外的 300 毫秒,而不是加载时间或至少 300 毫秒
2021-05-31 09:13:12
不幸的是,这个答案(好吧,它的一部分)在 Typescript 上下文中不起作用;幸运的是,stackoverflow.com/ questions/62594862/typescript-react-lazy 适用于第 1 部分的 Typescript,即要引入的额外延迟。
2021-06-01 09:13:12

正如 loopmode 所提到的,组件回退应该有一个超时。

import React, { useState, useEffect } from 'react'

const DelayedFallback = () => {
  const [show, setShow] = useState(false)
  useEffect(() => {
    let timeout = setTimeout(() => setShow(true), 300)
    return () => {
      clearTimeout(timeout)
    }
  }, [])

  return (
    <>
      {show && <h3>Loading ...</h3>}
    </>
  )
}
export default DelayedFallback

然后只需导入该组件并将其用作后备。

<Suspense fallback={<DelayedFallback />}>
       <LazyComponent  />
</Suspense>
这没有帮助。尽管如此,后备加载器只出现了很短的时间。有没有办法让它持续更长时间,因为即使在加载器消失之后,使用 react Route 加载组件也需要很长时间?
2021-06-19 09:13:12

回退组件动画Suspenselazy

@Akrom Sprinter 在快速加载时间的情况下有一个很好的解决方案,因为它隐藏了后备微调器并避免了整体延迟。这是 OP 请求的更复杂动画的扩展:

1. 简单变体:淡入+延迟显示

您只需添加一些@keyframes动画Fallback组成部分,无论是延迟其显示setTimeout和状态标志,或纯CSS(animation-fill-mode-delay这里使用)。

2.复杂的变体:淡入和出+延迟显示

这是可能的,但需要一个包装器。我们没有一个直接的API Suspense,以等待淡出动画,前Fallback组件被卸载。

让我们创建一个自定义useSuspenseAnimationHook,将给予的Promise延迟React.lazy足够长的时间,以便我们的结束动画完全可见:

// inside useSuspenseAnimation
const DeferredHomeComp = React.lazy(() => Promise.all([
    import("./routes/Home"), 
    deferred.promise // resolve this promise, when Fallback animation is complete
  ]).then(([imp]) => imp)
)

复杂变体的关键点

1.) useSuspenseAnimationHook 返回三个值:

  • hasImportFinished( boolean) → if true,Fallback可以开始淡出动画
  • enableComponent(回调)→Fallback在动画完成后调用它卸载
  • DeferredComponent → 动态加载的扩展惰性组件 import

2.) 监听animationendDOM 事件,以便我们知道动画何时结束。

您应该创建一个回退组件,它本身具有超时和可见状态。最初您设置了visible false。当回退组件被挂载时,它应该 setTimeout 来打开可见状态标志。确保您的组件仍处于挂载状态,或者在卸载组件时清除超时。最后,如果可见状态为 false,则在您的后备组件中渲染 null(或者例如只是阻塞/半透明覆盖但没有微调器/动画)

然后使用这样的组件,例如 <Loading overlay/>,作为后备。

你能提供一个例子吗?我们可以对 Suspense 组件说,如果回退组件被渲染并挂载,它必须保持挂载状态,例如至少1 秒吗?
2021-06-08 09:13:12

此外,我在使用 TypeScript 和 React 时遇到了类似的问题。所以,我也必须尊重typescript编译器,我继续采用一种具有无限延迟的方法,而且typescript也没有抱怨。从未解决的Promise😆

const LazyRoute = lazy(() => {
  return new Promise(resolve => () =>
    import(
      '../../abc'
    ).then(x => x e => null as never),
  );
});