问题
I am trying to implement a loading screen when changing routes in my Nextjs app ,for example /home -> /about.
My current implementation is as follows. I am setting the initial loaded state to false and then changing it on componentDidMount. I am also calling the Router.events.on function inside componentDidMount to change the loading state when the route change starts.
_app.js in pages folder
class MyApp extends App {
constructor(props) {
super(props);
this.state = {
loaded: false,
};
}
componentDidMount() {
this.setState({ loaded: true });
Router.events.on('routeChangeStart', () => this.setState({ loaded: false }));
Router.events.on('routeChangeComplete', () => this.setState({ loaded: true }));
}
render() {
const { Component, pageProps } = this.props;
const { loaded } = this.state;
const visibleStyle = {
display: '',
transition: 'display 3s',
};
const inVisibleStyle = {
display: 'none',
transition: 'display 3s',
};
return (
<Container>
<>
<span style={loaded ? inVisibleStyle : visibleStyle}>
<Loader />
</span>
<span style={loaded ? visibleStyle : inVisibleStyle}>
<Component {...pageProps} />
</span>
</>
</Container>
);
}
}
This works perfectly fine but I feel like there may be a better solution more elegant solution. Is this the only way which isn't cumbersome to implement this loading feature or is there an alternative ?
回答1:
Why not use nprogress
as follow in _app.js
import React from 'react';
import Router from 'next/router';
import App, { Container } from 'next/app';
import NProgress from 'nprogress';
NProgress.configure({ showSpinner: publicRuntimeConfig.NProgressShowSpinner });
Router.onRouteChangeStart = () => {
// console.log('onRouteChnageStart triggered');
NProgress.start();
};
Router.onRouteChangeComplete = () => {
// console.log('onRouteChnageComplete triggered');
NProgress.done();
};
Router.onRouteChangeError = () => {
// console.log('onRouteChnageError triggered');
NProgress.done();
};
export default class MyApp extends App { ... }
Link to nprogress.
You also need to include style file as well. If you put the css file in static
directory, then you can access to the style as follow:
<link rel="stylesheet" type="text/css" href="/static/css/nprogress.css" />
Make sure the CSS is available in all pages...
It will work for all you routes changing.
回答2:
Using the new hook api, this is how I would do it..
function Loading() {
const router = useRouter();
const [loading, setLoading] = useState(false);
useEffect(() => {
const handleStart = (url) => (url !== router.pathname) && setLoading(true);
const handleComplete = (url) => (url !== router.pathname) && setLoading(false);
router.events.on('routeChangeStart', handleStart)
router.events.on('routeChangeComplete', handleComplete)
router.events.on('routeChangeError', handleComplete)
return () => {
router.events.off('routeChangeStart', handleStart)
router.events.off('routeChangeComplete', handleComplete)
router.events.off('routeChangeError', handleComplete)
}
})
return loading && (<div>Loading....{/*I have an animation here*/}</div>);
}
Now <Loading/>
is going to show up whenever the route will change...
I animate this using react-spring, but you can use any library you prefer to do this.
You can even take a step further and modify when the component shows up by modifying the handleStart
and handleComplete
methods that gets a url
.
来源:https://stackoverflow.com/questions/55624695/loading-screen-on-next-js-page-transition