简体   繁体   中英

How to use dynamic import one time only with NextJS

I am building an App with NextJS, I'd like to render loading icon while fetching data or loading some pages. Currently I have to insert Loading component into each compomnent, for example if you have HomePage, you have to import Loading to HomePage, then if you have ProductList, you will also have to import Loading into ProductList, .... While I think it's better if I can import Loading one time only and apply for whole app, like React Lazy + suspend. The docs of NextJS only guides you how to do with each Component only. I have tried React Lazy + Suspend but this didn't work as well. Could you please advise should I put dynamic import.

Appreciate any advice.

file pages/_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;

If you want to add global loading whenever the data is fetching, you can try to put the loading state in the redux. A way to accomplish it might be like this.

_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>
    </>
  );
}

PageComponent

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>;
}

However, I think to show the global loading state in every page doesn't seems reasonable. Because most of the time, it just call the api and then render a portion of the part on the screen (not the entire screen). The better way would be show the loading icon only on a small part of the screen which would show the response data later from the api.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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