如何使用 React Suspense 应用平滑过渡?

问题描述

我用懒惰和悬念来延迟加载一个组件。它有效,但过渡非常原始。有没有一种简单的方法来应用平滑过渡而不用关键帧不透明度动画包裹每个暂停的组件(在每次重新渲染时它会再次触发,我不想要这个。只有在组件准备好显示时才进行过渡) ?

基本代码

const Foo = lazy(()=> import("./Foo"))

function Component (){
  return (
    <Suspense fallback={<Loader/>}>
     <Foo/>
    </Suspense>
  )
}

解决方法

我遇到了类似的问题,我通过创建一个 <Lazy ... /> 组件解决了它。这是我的解决方案,也许可以帮到你。

import React from "react"
import PleaseWait from "../please-wait"

export default function Lazy<P>(
    props: P & {
        factory: () => Promise<{ default: (props: P) => JSX.Element }>
    }
) {
    const { factory } = props
    const [element,setElement] = React.useState<JSX.Element | null>(null)
    React.useEffect(() => {
        setElement(null)
        factory().then(mod => setElement(mod.default(props)))
    },[factory])
    return <PleaseWait>{element}</PleaseWait>
}

这是我如何使用它:

<Lazy
    factory={() => import("./menu")}
    traceMsg={props.myMessage}
/>

我在 "./menu" 中定义的组件需要 traceMsg 有 prop。 一旦您编写了 factory={() => import("./menu")},TypeScript 就足够智能,可以让 VSCode 为您提供 traceMsg 的智能感知。

至于组件<PleaseWait/>,这取决于您的需求。就我而言,我有这个:

export interface PleaseWaitViewProps {
    className?: string
    children?: JSX.Element | JSX.Element[] | string | null
}

export default function PleaseWaitView(props: PleaseWaitViewProps) {
    const { children } = props
    return (
        <div className={getClassNames(props)}>
            <div className={`element ${children ? "show" : "hide"}`}>
                {children}
            </div>
            <div className={`fallback ${children ? "hide" : "show"}`}>
                {/* Whatever spinning animation you want... */}
            </div>
        </div>
    )
}

当然,这不是一个完美的解决方案,因为您的组件最终会被两个 <div> 包围。