Setting up a loader when changing a Nextjs page
Why Implement a Loader?
Implementing a loader allows the user to understand what is happening on the site. Indeed, it would be unfortunate if nothing happened on our page... The loader communicates with the user, showing them that we have successfully received their request.
Prerequisites
Implementing this loader will be done in the Layout of your NextJS website. Therefore, you must have created a Layout.js
file (or an equivalent name) that will serve as the base for your pages in your project.
What is the Layout?
The layout is a component that will be present throughout the website. Its JSX and CSS code will be applied to all pages of the site.
Typically, we include in the layout the base of each of our pages: the head tags, CSS styles, as well as headers and footers.
Creating the Loader
We will create a function that checks if the URL changes. If it does, we change the state using useState
to activate or deactivate the loader by setting it to true
. In this case, we return JSX code that will be displayed while the new page is loading.
In the following case, we simply write a loading text.
1. We start by writing a function where we call the router and create the loading state:
function Loading() {
const router = useRouter();
const [loading, setLoading] = useState(false);
}
2. We add a useEffect
that will check if the URL changes.
useEffect(() => {
const handleStart = (url) => (url !== router.asPath) && setLoading(true);
const handleComplete = (url) => (url === router.asPath) && 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)
}
})
When the page change starts, we call the handleStart
function, which sets the loading state to TRUE.
When it completes or fails, we call the handleComplete
function, which sets the loading state to FALSE.
3. Finally, we return JSX.
return loading && (
<>
Loading...
</>
);
This JSX is the content that is displayed during the page transition.
Final Code
function Loading() {
const router = useRouter();
const [loading, setLoading] = useState(false);
useEffect(() => {
const handleStart = (url) => (url !== router.asPath) && setLoading(true);
const handleComplete = (url) => (url === router.asPath) && 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 && (
<>
Loading...
</>);
}
Next, we need to add the <Loading /> tag in the JSX of the component. This allows us to call the previously created function. The loader will thus appear exactly where you place the tag.
For example - Layout.js:
// Component
import Loader from "loader.js";
export default function Layout(props) {
return (
<>
{/* All your components */}
<Loader />
</>
)
}