首页 > 解决方案 > 如何使用 NextJS 只使用一次动态导入

问题描述

我正在使用 NextJS 构建一个应用程序,我想在获取数据或加载某些页面时呈现加载图标。目前我必须将 Loading 组件插入到每个组件中,例如,如果您有 HomePage,则必须将 Loading 导入 HomePage,然后如果您有 ProductList,您还必须将 Loading 导入 ProductList,....虽然我认为是如果我可以只导入一次加载并申请整个应用程序,比如 React Lazy + 暂停,那就更好了。NextJS 的文档仅指导您如何处理每个组件。我已经尝试过 React Lazy + Suspend 但这并不奏效。您能否建议我是否应该进行动态导入。

感谢任何建议。

文件页面/_app.js:

function MyApp({ Component, pageProps }) {
    return (
        <>
            <Head>
                <meta charSet="utf-8" />
                <meta name="viewport" content="width=device-width, initial-scale=1" />
                <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossOrigin="anonymous" />
                <title>Hello, world!</title>
                <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossOrigin="anonymous"></script>
                <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossOrigin="anonymous"></script>
                <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossOrigin="anonymous"></script>
            </Head>

            <Header />

            <main className="pt-3">
                <Component {...pageProps} />
            </main> 

            <Footer />
        </>
    )
}

export default MyApp;

标签: javascriptreactjsreact-reduxnext.jsrouter

解决方案


如果要在获取数据时添加全局加载,可以尝试loading state将 实现它的方法可能是这样的。

_app.js

import { useSelector, useDispatch } from 'redux';

function MyApp({ Component, pageProps }) {
  const isLoading = useSelector((state) => state.isLoading);
  
  const dispatch = useDispatch();
  
  useEffect(() => {
    Router.events.on('routeChangeComplete', () => {
      // when route has been changed complete, dispatch an action which would make the loading state to be true
      dispatch({ type: 'CHANGE_LOADING_STATE', payload: true });
  }, [])

  return (
    <WithLoadingComponent>
       <Component {...pageProps} />
    </WithLoadingComponent>
  );
}

WithLoadingComponent

import { useSelector } from 'redux';
import Router from 'next/router';

function WithLoadingComponent(props) {
  const isLoading = useSelector((state) => state.isLoading);
  
  return (
    <>
      {isLoading && <GlobalLoadingComponent />}
      <div className={isLoading ? 'loading' : ''}>{props.children}</div>
      <style jsx>{`
        .loading {
          visibility: hidden;
        }
      `}</style>
    </>
  );
}

页面组件

import { useDispatch } from 'redux';

function PageComponent(props) {
  const dispatch = useDispatch();

  useEffect(() => {
    // Call api to fetch data
    (async () => {
      try {
        const data = await fetch('https://www.xxyyzz.com/api');
        console.log(data);
        dispatch({ type: 'CHANGE_LOADING_STATE', payload: false });
      } catch (error) {
        dispatch({ type: 'CHANGE_LOADING_STATE', payload: false });
      }
    })();
  }, []);

  return <div>Page component</div>;
}

但是,我认为在每个页面中显示全局加载状态似乎并不合理。因为大多数时候,它只是调用api,然后在屏幕上渲染一部分(而不是整个屏幕)。更好的方法是仅在屏幕的一小部分显示加载图标,稍后将显示来自 api 的响应数据。


推荐阅读