检测动态导入的组件是否已加载到 Nextjs 中

Gon*_*o.- 8 typescript reactjs next.js

这是我的场景的简化

import React, { useState } from 'react';
import dynamic from 'next/dynamic';

const DynamicImportedComponent = dynamic(() => import('Foo/baz'), {
  ssr: false,
  loading: () => <p>loading..</p>
});


const MyComponent: React.FC = () => {
  const [show, setShow] = useState(false)

  const variableComponent = <SomeStyledComponent styled={show}>value of show is {show.toString()}</SomeStyledComponent>
  return (
    <>
    {variableComponent}
    { show && <DynamicImportedComponent />}
    <button onClick={() => setShow(!show)}>toggle</button>
    </>
  )
}
Run Code Online (Sandbox Code Playgroud)

有一个切换状态允许我显示或不显示动态加载的组件

我有一个始终呈现的组件,但基于切换可能会显示不同的样式。
当用户单击按钮时,状态设置为 true 并且动态加载组件。与此同时,nextjs 渲染加载消息。到目前为止,一切都很好

但是,我希望在加载variableComponent时不可见。DynamicImportedComponent这是因为它有一些样式在加载程序中看起来不太好。有没有办法检测组件是否已完成加载?加载组件后,我将variableComponent像平常一样渲染

我在想一些类似的事情

{(DynamicImportedComponent.loaded || !DynamicImportedComponent.isLoading) && variableComponent}
Run Code Online (Sandbox Code Playgroud)

但这似乎并不存在。

我正在使用最新版本的 React 和 nextjs 以及 typescript

Joh*_*ohn 6

我也遇到了这个问题。目前还没有执行此操作的标准方法,但 Nextjs 维护者之一在 Nextjs 存储库的讨论中建议了以下内容:

我们尽可能地镜像 React.lazy (同时还提供缺少的加载状态,因为 Suspense 在服务器端不起作用)。Suspense 可能会解决您的问题,因为它允许在一项挂起时(例如动态组件)为树的一部分显示旋转器。然而,如上所述,Suspense 目前在服务器端不可用。

您可能要做的一件事是在上下文值中传递状态并在加载组件中传递 setState

我发现使用 React Context 的建议效果很好。

我的项目中的示例代码

const ToolbarTray: FunctionComponent<{}> = () => {
  const { isDialogOpen, closeDialog, openDialog } = useDialogState();

  const [ isDialogLoading, setDialogLoadingStatus ] = useState(false);

  return (
    <DynamicLoadingContext.Provider value={setDialogLoadingStatus}>
      <Button onClick={openDialog}>
        {isDialogLoading ? <CircularProgress /> : <EditIcon />}
      </Fab>

      {isDialogOpen && <EditPersonDialog onClose={closeDialog} />}
    </DynamicLoadingContext.Provider>
  );
};

const EditPersonDialog = dynamic(() => import('~/dialogs/edit-person-dialog'), {
  ssr: false,
  loading: () => {
    const setLoading = useContext(DynamicLoadingContext);

    useEffect(() => {
      setLoading(true);
      return () => setLoading(false);
    }, [setLoading]);

    return null;
  },
});
Run Code Online (Sandbox Code Playgroud)