如何在 Next.js 中构建进度条指示器
在过去的几年中,Next.js 进一步确立了其作为 基于 React 构建的最受欢迎的后端框架 的地位。 最近的几项更新增强或添加到此框架的现有功能。 一个例子是它能够同时在服务器端和客户端呈现页面以及它的集成路由系统,这使得这些呈现器之间的导航无缝。
但是,这些渲染器之间的过渡并不像您想象的那么顺利。 Next.js 需要一点时间在页面之间进行路由,尤其是到服务器端呈现的页面,因为这些页面是根据请求呈现的。 每次用户尝试路由到另一个页面时,站点可能会出现暂时冻结,这可能会导致用户体验不佳。
本教程将通过演示如何在 Next.js 应用程序中更改路由时构建和显示进度条指示器来解决此问题。 我们将使用自定义 CSS 创建加载器组件的一个版本,我们还将展示如何使用第三方库来添加动画。
内容
-
先决条件
-
什么是 Next.js 路由器事件?
-
入门
-
创建加载器组件
-
创建路由器事件
-
添加动画
-
使用 NProgress
-
使用 React 微调器
-
先决条件
要学习本教程,您需要以下内容:
-
Next.js 和 React 的基础知识
-
的基本理解 Next.js 路由系统
什么是 Next.js 路由器事件?
路由器事件是事件监听器,允许我们通过 Router目的。 该对象提供了一些属性,我们可以使用这些属性来监听 Next.js 路由器中发生的不同事件,并根据这些事件执行某些操作。
例如,如果我们想记录 "route is changing"每次用户点击一个链接并导航到另一个页面时,我们可以使用 "routeChangeStart" 路由器 事件,如下所示:
Router.events.on("routeChangeStart", (url)=>{ console.log(“route is changing”) })
这 routeChangeStart当路由开始改变时触发事件。 它返回一个回调函数,我们可以使用它来运行代码和操作。 正如您在上面的代码中看到的,该事件触发了一个回调函数,该函数记录了 "route is changing"字符串到控制台。
以下是一些受支持的 Next.js 路由器事件的列表:
-
routeChangeStart: 当路由开始改变时触发
-
routeChangeComplete: 路由更改完成时触发
-
routeChangeError:在更改路由时发生错误或取消路由加载时触发
-
beforeHistoryChange: 在更改路由器的路由历史之前触发
访问 Next.js 文档 以了解有关这些路由器事件的更多信息。
入门
我假设您已经设置了 Next.js 项目。 如果没有,您可以 fork 示例项目的 CodeSandbox 来跟进。
超过 20 万开发人员使用 LogRocket 来创造更好的数字体验 了解更多 →
本教程中使用的示例项目是一个基于 Rick and Morty 情景喜剧的简单 Next.js 应用程序。 示例应用程序包含三个页面:主页、关于和字符。 前两个页面是客户端呈现的,而字符页面是服务器端呈现的。
在 Characters 页面中,我们使用 getServerSideProps获取和显示数据的 从Rick and Morty API 函数:
const Characters = ({ data }) => { return ( <div className={styles.container}> ... </div> ); } export default Characters; export async function getServerSideProps() { const delay = (s) => new Promise(resolve => setTimeout(resolve, s)) const res = await fetch("https://rickandmortyapi.com/api/character") await delay(2000) const data = await res.json(); return { props: {data} } }
Characters 页面是在初始加载时预先生成的,但只有在用户单击该路由时才会完成获取请求。 这样,页面的内容只会在请求完成后才显示给用户,这可能需要一些时间。
我们将使用 Next.js 路由器事件显示进度条指示器,而不是让用户对那几秒钟内发生的事情一无所知。
出于这个原因,我们使用 delay承诺,如下面的代码所示:
const delay = (s) => new Promise(resolve => setTimeout(resolve, s)) ... await delay(2000) ...
这个 delay当我们转到 Characters 页面时,会给我们时间来展示进度指示器。
要完成设置,请在终端中运行以下命令来安装两个第三方库 NProgress 和 React Spinners,我们将在本教程的后面部分使用它们。
npm i --save nprogress react-spinners
这些库是动画进度条提供程序; 我们将在本文后面详细讨论它们。
创建加载器组件
接下来,我们需要创建一个组件来包装进度指示器元素。
首先创建一个组件文件夹并添加一个 Loader.js里面的文件。
现在,打开 loader.js文件并添加以下代码:
const Loader = () => { return ( <div className={styles.wrapper}> <div className={styles.loader}> </div> </div> ); } export default Loader;
代码包含两个 div标签,一个 wrapper div 和一个嵌套的 loader分区。 如果您打算使用 CSS 创建自定义进度条指示器,这些元素将派上用场。
来自 LogRocket 的更多精彩文章:
-
不要错过 The Replay 来自 LogRocket 的精选时事通讯
-
使用 React 的 useEffect 优化应用程序的性能
-
之间切换 在多个 Node 版本
-
了解如何 使用 AnimXYZ 为您的 React 应用程序制作动画
-
探索 Tauri ,一个用于构建二进制文件的新框架
-
比较 NestJS 与 Express.js
-
发现 TypeScript 领域中使用的流行 ORM
接下来,导航到 styles文件夹内的项目根文件夹,并为加载器组件创建一个新的 CSS 模块。
在模块内部,添加以下代码:
.wrapper{ width: 100%; height: 100vh; position: absolute; top: 0; left: 0; background-color: rgb(0, 0, 0, 0.3); backdrop-filter: blur(10px); display: flex; justify-content: center; align-items: center; z-index: 99; } /*code for custom loading icon*/ .loader{ border: 10px solid #f3f3f3; border-radius: 50%; border-top: 10px solid #505050; width: 60px; height: 60px; animation: spin 2s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
上面的代码将使 wrapperdiv 使用背景过滤器占据整个视口,并将每个子元素居中(在这种情况下, loaderdiv) 内 wrapper.
注意, CSS 内的属性 loader 选择器用于自定义 CSS 进度条指示器; 如果您更喜欢使用 NProgress 或 React Spinners 库,请忽略这一点
现在,回到 loader.js组件并在代码块顶部导入 CSS 模块,如下所示:
import styles from '../styles/Loader.module.css'
接下来,我们将继续创建路由器事件。
创建路由器事件( routeChangeStart, routeChangeComplete, 和 routeChangeError)
Since we’ll be displaying the progress bar indicator on every page route, rather than on a particular route, we’re going to call the Router event listeners directly inside the _app.js component.
If your project doesn’t have an _app.js component, go to the pages folder, create a new _app.js file, and add the following code:
import '../styles/globals.css' function MyApp({ Component, pageProps }) { return ( <Component {...pageProps} /> ) } export default MyApp
Next.js 将使用 _app.js组件来初始化我们项目中的页面。 我们可以覆盖它并控制初始化。
接下来,导入 Router目的, useState, 和 useEffect里面的挂钩 _app.js组件,如下所示:
import Router from 'next/router' import { useState, useEffect } from 'react';
随着 Router导入对象,我们可以开始声明事件。
我们希望能够跟踪路由何时开始更改、已更改以及何时在更改路由或取消路由加载时发生错误。 因此,我们将订阅 routeChangeStart, routeChangeComplete, 和 routeChangeError事件,分别。
首先,创建一个 isLoading状态变量使用 useState我们之前导入的钩子并传递给它一个默认的布尔值 false.
const [isLoading, setIsLoading] = useState(false);
然后,调用 useEffect挂钩并添加 routeChangeStart其回调函数内的事件侦听器。
useEffect(() => { Router.events.on("routeChangeStart", (url)=>{ }); }, [Router])
接下来,设置的值 isLoading状态变量为 true在事件的回调函数中,如下所示:
Router.events.on("routeChangeStart", (url)=>{ setIsLoading(true) });
现在,再创建两个 Router第一个下方的事件侦听器,一个用于 routeChangeComplete一个用于 routeChangeError:
Router.events.on("routeChangeComplete", (url)=>{ setIsLoading(false) }); Router.events.on("routeChangeError", (url) =>{ setIsLoading(false) });
这 routeChangeComplete和 routeChangeErrorevents 将负责结束加载会话,该会话由 routeChangeStart事件,当路由完全改变或发生错误时。
完成上述步骤后,您的 useEffect函数应如下所示:
useEffect(() => { Router.events.on("routeChangeStart", (url)=>{ setIsLoading(true) }); Router.events.on("routeChangeComplete", (url)=>{ setIsLoading(false) }); Router.events.on("routeChangeError", (url) =>{ setIsLoading(false) }); }, [Router])
现在我们有了一个对 Next.js 路由器内部发生的不同事件做出反应的状态。
接下来,我们将导入我们之前创建的加载器组件,并根据 isLoading多变的。
import Router from 'next/router' import { useState, useEffect } from 'react'; import Loader from '../component/loader'; function MyApp({ Component, pageProps }) { const [isLoading, setIsLoading] = useState(false); useEffect(() => { ... }, [Router]) return ( <> {isLoading && <Loader/>} <Component {...pageProps} /> </> ) } export default MyApp
我们在这里所做的事情是不言自明的。 我们导入加载器组件并有条件地将其渲染到视图。
如果您使用我们之前创建的自定义 CSS 加载器,当您尝试在应用程序中进行路由时,您应该会看到与下图类似的加载屏幕。
添加动画
上一节中显示的进度指示器是使用自定义 CSS 构建的。 现在,让我们尝试使用两个库添加动画:NProgress 和 React Spinners。
使用 NProgress
NProgress 是一个轻量级库,可让我们在视口顶部显示逼真的涓涓动画以指示加载进度,而不是使用动画加载图标。
要使用 NProgress,请导入 NProgress里面的函数 _app.js组件,如下所示:
import NProgress from 'nprogress'
该函数有一组方法可以用来显示和配置进度条动画。 以下是一些可用的方法:
-
start: 显示进度条
-
set: 设置百分比
-
inc: 增加一点
-
done: 完成进度
-
configure: 配置偏好
请参阅 NProgress 官方文档 以了解有关这些方法的更多信息。
Next, call the function’s start() and done() methods inside the routeChangeStart and routeChangeComplete event callbacks, respectively:
Router.events.on("routeChangeStart", (url)=>{ Nprogress.start() }) Router.events.on("routeChangeComplete", (url)=>{ Nprogress.done(false) });
最后,我们将通过以下 CDN 链接将与 NProgress 相关的 CSS 添加到我们的项目中:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nprogress/0.2.0/nprogress.min.css" integrity="sha512-42kB9yDlYiCEfx2xVwq0q7hT4uf26FUgSIZBK8uiaEnTdShXjwr8Ip1V4xGJMg3mHkUt9nNuTDxunHF0/EgxLQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
为此,请导入 Head来自 Next.js 的组件并在声明中嵌套 CDN 链接,如下所示:
... import Head from "next/head" function MyApp({ Component, pageProps }) { ... return ( <> <Head> <link rel="stylesheet" ... /> </Head> <Component {...pageProps} /> </> ) }
如果您保存进度并在浏览器中单击路线,您应该会在视口顶部看到一个进度条和一个旋转图标,类似于下图所示。
要禁用视口右上角的旋转图标,请调用 configure方法并将其传递给一个对象 showSpinner属性和值设置为 false.
Nprogress.configure({showSpinner: false});
现在,如果您保存代码并返回浏览器,旋转图标应该会消失。
使用 React 微调器
React Spinners 是一个轻量级库,由一系列基于 React 的进度指示器组成。 该库提供了各种动画加载图标,可用于指示加载进度。
进度指示器作为组件从库中公开。 这些组件接受我们可以用来自定义它们的速度、大小、加载状态和颜色的道具。
要使用 React Spinners,请返回 loader.js组件并导入微调器组件,如下所示:
import {HashLoader} from 'react-spinners'
选择和配置您喜欢的微调器 您可以从产品页面 。
接下来,将微调器组件嵌套在 wrapperdiv 并保存您的进度。
<div className={styles.wrapper}> <HashLoader color="#eeeeee" size={80} /> </div>
现在,如果您返回浏览器,当您在页面之间进行路由时,您应该会看到一个漂亮的动画加载图标。
HideRarInImage文件伪装隐藏,成年人必备软件,老司机看完秒懂!
结论
在本文中,我们介绍了 Next.js 路由器事件并演示了如何使用它们来跟踪路由活动并显示进度条指示器。
我们演示了如何创建一个加载器组件,该组件根据路由器发出的事件呈现进度条指示器,还使用 NProgress 和 React Spinners 库添加了自定义加载器。
LogRocket :全面了解生产 Next.js 应用程序
调试 Next 应用程序可能很困难,尤其是当用户遇到难以重现的问题时。 如果您对监控和跟踪状态、自动显示 JavaScript 错误以及跟踪缓慢的网络请求和组件加载时间感兴趣,请 尝试 LogRocket 。
LogRocket 就像一个用于网络和移动应用程序的 DVR,几乎可以记录下一个应用程序上发生的所有事情。 无需猜测问题发生的原因,您可以汇总并报告问题发生时应用程序所处的状态。 LogRocket 还监控您的应用程序的性能,并使用客户端 CPU 负载、客户端内存使用情况等指标进行报告。
LogRocket Redux 中间件包为您的用户会话增加了一层额外的可见性。 LogRocket 记录来自 Redux 存储的所有操作和状态。