如何在 Next.js 中实现加载屏幕
Posted
技术标签:
【中文标题】如何在 Next.js 中实现加载屏幕【英文标题】:How to implement loading screen in Next.js 【发布时间】:2020-07-25 19:37:02 【问题描述】:我是 nextjs 的新手,使用 nextjs v9.3
、next-redux-wrapper v5
、@material-ui/core v4.2
和 custom express server
。
我试图在我的 Nextjs 应用程序中更改路线时实现加载屏幕,因此我使用 framer motion 进行页面之间的转换并且工作正常,但现在 如何在更改路线时使用加载组件?
我用了这些方法,但是没用:
Loading Screen on next js page transition How can I use a loading component instead of nprogress?我目前的实现如下:
_app.js
import React, useEffect from "react";
import ThemeProvider from "@material-ui/core/styles";
import CssBaseline from "@material-ui/core";
import theme from "../lib/theme";
import withRedux from "next-redux-wrapper";
import Provider from "react-redux";
import reduxStore from "../store/store";
import PersistGate from "redux-persist/integration/react";
import AnimatePresence from "framer-motion";
import Navbar from "../components/Navbar";
import Meta from "../components/Meta";
function MyApp(props)
useEffect(() =>
const jssStyles = document.querySelector("#jss-server-side");
if (jssStyles && jssStyles.parentNode)
jssStyles.parentNode.removeChild(jssStyles);
, []);
const Component, pageProps, store, router = props;
return (
<ThemeProvider theme=theme>
<CssBaseline />
<Provider store=store>
<PersistGate persistor=store.__PERSISTOR loading=null>
<Meta/>
<Navbar ...props />
<AnimatePresence exitBeforeEnter>
<Component ...pageProps key=router.route/>
</AnimatePresence>
</PersistGate>
</Provider>
</ThemeProvider>
);
export default withRedux(reduxStore)(MyApp);
更新
`___-_-_-_-_my solution_-_-_-_-___`
方法1:在next.js v9.3中我使用framer-motion
import React,
useEffect,
useState,
from "react";
import ThemeProvider as MaterialThemeProvider from "@material-ui/core/styles";
import ThemeProvider as StyledThemeProvider from "styled-components";
import CssBaseline from "@material-ui/core";
import AnimatePresence, motion from "framer-motion";
import theme from "../lib/theme";
import Layout from "../components/Layout";
import Loader from "react-loader-spinner";
function MyApp(props)
const Component, pageProps, router = props;
// blow useState & useEffect for tracking change route
const [isRouteChanging, setIsRouteChanging] = useState(false);
useEffect(() =>
const routeChangeStartHandler = () => setIsRouteChanging(true);
const routeChangeEndHandler = () => setIsRouteChanging(false);
router.events.on("routeChangeStart", routeChangeStartHandler);
router.events.on("routeChangeComplete", routeChangeEndHandler);
router.events.on("routeChangeError", routeChangeEndHandler);
return () =>
router.events.off("routeChangeStart", routeChangeStartHandler);
router.events.off("routeChangeComplete", routeChangeEndHandler);
router.events.off("routeChangeError", routeChangeEndHandler);
;
, []);
// useEffect config material-ui
useEffect(() =>
// Remove the server-side injected CSS.
const jssStyles = document.querySelector("#jss-server-side");
if (jssStyles && jssStyles.parentNode)
jssStyles.parentNode.removeChild(jssStyles);
, []);
return (
<StyledThemeProvider theme=theme>
<MaterialThemeProvider theme=theme>
<CssBaseline />
/*animation for each page when route changes*/
<Layout>
isRouteChanging ? (
<motion.div
initial=
opacity: 0,
height: "90vh",
display: "flex",
justifyContent: "center",
alignItems: "center",
animate=
opacity: 1,
exit=
opacity: 0,
>
<Loader
type="Grid"
color=theme.spinnerColor
height=80
width=80
/>
</motion.div>
) : (
<AnimatePresence exitBeforeEnter>
<Component ...pageProps key=router.route />
</AnimatePresence>
)
</Layout>
</MaterialThemeProvider>
</StyledThemeProvider>
);
export default MyApp;
方法 2:在 next.js v10 中,我使用了 "nprogress": "^0.2.0"
import React, useEffect from "react";
import Router from "next/router";
// MUI Core
import CssBaseline from "@material-ui/core/CssBaseline";
import ThemeProvider from "@material-ui/core/styles";
// Utils
import theme from "Utils/theme";
// NProgress
import NProgress from "nprogress";
//Binding events.
Router.events.on("routeChangeStart", () => NProgress.start());
Router.events.on("routeChangeComplete", () => NProgress.done());
Router.events.on("routeChangeError", () => NProgress.done());
function MyApp( Component, pageProps)
// useEffect config material-ui
useEffect(() =>
// Remove the server-side injected CSS.
const jssStyles = document.querySelector("#jss-server-side");
if (jssStyles && jssStyles.parentNode)
jssStyles.parentNode.removeChild(jssStyles);
, []);
return (
<Provider store=store>
<ThemeProvider theme=theme>
<CssBaseline />
<Component ...pageProps />
</ThemeProvider>
</Provider>
);
export default MyApp;
【问题讨论】:
请do not upload images of code 【参考方案1】:我是这样做的。在_app.tsx
:
import useRouter from 'next/router';
const MyApp = (
MainComponent,
pageProps,
) =>
const router = useRouter();
const [pageLoading, setPageLoading] = React.useState<boolean>(false);
React.useEffect(() =>
const handleStart = () => setPageLoading(true); ;
const handleComplete = () => setPageLoading(false); ;
router.events.on('routeChangeStart', handleStart);
router.events.on('routeChangeComplete', handleComplete);
router.events.on('routeChangeError', handleComplete);
, [router]);
return (
...
pageLoading
? (<div>Loading</div>)
: <MainComponent ...pageProps />
...
)
【讨论】:
【参考方案2】:这可能会有所帮助,您可以将此组件放在布局组件中并用它包装_app.js
或直接将其导入到_app.js
:
import React from 'react';
import Router from 'next/router';
import CustomLoadingScreen from './components/CustomLoadingScreen'; // example
Router.onRouteChangeStart = () =>
console.log('onRouteChangeStart Triggered');
<CustomLoadingScreen />;
;
Router.onRouteChangeComplete = () =>
console.log('onRouteChangeComplete Triggered');
<CustomLoadingScreen />;
;
Router.onRouteChangeError = () =>
console.log('onRouteChangeError Triggered');
<CustomLoadingScreen />;
;
您可以设计<CustomLoadingScreen />
,以便在调用时接管设备的整个视图。
【讨论】:
以上是关于如何在 Next.js 中实现加载屏幕的主要内容,如果未能解决你的问题,请参考以下文章