当前位置: 首页 > news >正文

Next.js加载异步组件 骨架屏

Next.js 中有两种处理页面加载的方式,一种是 Loading UI 一种是 Streaming。接下来我将介绍这两种的区别,以及实际的业务场景。

当我们进入某个页面时,需要获取页面数据,可能是从数据库读取也有可能是 API 服务,总之这是一个异步任务,我们可以在获取数据过程中提示用户数据正在加载,比如放置一些骨架屏,提升用户的体验。

如果不对这些进行处理,使用体验会大打折扣。

假设我们有一个场景,进入 /posts 页面后获取所有的文章数据。

app/posts/page.tsx

import Link from "next/link";const PostsPage = async () => {const posts = await fetch("https://jsonplaceholder.typicode.com/posts").then((response) => response.json());// await new Promise((resolve) => setTimeout(resolve, 2000));return (<div className="p-10 max-w-3xl mx-auto"><ul className="list-decimal">{posts.map((post) => (<li key={post.id} className=""><h2 className="text-xl font-semibold my-2"><Link href={`/posts/${post.id}`} className="hover:underline">{post.title}</Link></h2><p>{post.body}</p></li>))}</ul></div>);
};export default PostsPage;

可以解开上面的注释延长加载时间。

如果我们从首页进入到 /posts 页面,不会立即进入,需要等待 await 之后才会进入页面,这个等待时间就取决于我们的网络了,当网络较差时,可能很久才获取数据,这就大大影响了用户体验。

Loading UI

在 posts 同级目录创建 app/posts/loading.tsx 文件:
(ps:我项目使用的 TypeScript,如果是 JavaScript 则为 jsx 后缀)

const PostsLoading = () => {return <p>Loading...</p>;
};export default PostsLoading;

这样当我们进入 /posts 页面后不会等待数据加载完成后才进入页面,而是直接进入 /posts 页面,数据加载过程中显示的内容为 loading.tsx 文件的内容,我们就可以写一些文字提示或者骨架屏之类的内容。

Streaming (Suspense)

另一种方式,也是比较推荐的方式:Streaming (Suspense),流式传输。

比如我们一个页面有多个异步组件,有文章、评论等等,如果我们使用上述第一种方案,页面会等所有的数据加载完成才渲染,而通过 Suspense 可以对每一个组件异步渲染。

image.png

React 18 引入了 Suspense 组件,支持在组件树中展示异步组件。Next.js 利用这一特性,让开发者可以定义一个组件在加载期间显示的备选内容。

通过 Suspense,你可以在组件等待数据时显示一个备用 UI,这样用户就不会看到不完整的空白界面。一旦数据加载完毕,React 将渲染实际的组件。这种异步加载方式特别适用于大型组件或数据,它们可能需要长时间来加载和渲染。

新建 app/posts2/page.tsx 文件:

import Link from "next/link";
import { Suspense } from "react";const Posts2Page = () => {return (<div><Suspense fallback={<PostsSkeleton />}><PostList /></Suspense></div>);
};const PostsSkeleton = () => {return (<div className="p-10 max-w-3xl mx-auto"><ul className="space-y-2 list-decimal">{[...Array(5).keys()].map((i) => (<li key={i} className="space-y-2"><divclassName="animate-pulse h-7 w-1/2 bg-slate-200 rounded duration-1000"style={{animationDelay: `${i * 0.05}s`,}}></div><divclassName="animate-pulse h-5 w-full bg-slate-200 rounded duration-1000"style={{animationDelay: `${i * 0.05}s`,}}></div><divclassName="animate-pulse h-5 w-3/4 bg-slate-200 rounded duration-1000"style={{animationDelay: `${i * 0.05}s`,}}></div></li>))}</ul></div>);
};const PostList = async () => {const posts = await fetch("https://jsonplaceholder.typicode.com/posts").then((response) => response.json());await new Promise((resolve) => setTimeout(resolve, 1000));return (<div className="p-10 max-w-3xl mx-auto"><ul className="list-decimal">{posts.map((post) => (<li key={post.id} className=""><h2 className="text-xl font-semibold my-2"><Link href={`/posts/${post.id}`} className="hover:underline">{post.title}</Link></h2><p>{post.body}</p></li>))}</ul></div>);
};export default Posts2Page;

Posts2Page 使用 Suspense 组件包裹 PostList 组件。当 PostList 组件在加载数据时,Suspense 会显示它的 fallback 属性,也就是 PostsSkeleton 组件。

PostsSkeleton 是一个骨架屏组件,用于在数据加载时显示。它会显示5个文章的占位符。

PostList 是一个异步组件,从 https://jsonplaceholder.typicode.com/posts 这个 URL 获取文章数据,然后显示出来。

2023-12-13_15-38-10.gif

最后,如果文章对您有所帮助,还希望能够点赞、收藏、关注,您的每一次点击都会为我带来无穷的动力来写出更好的文章。

相关文章:

  • 【Vue原理解析】之响应式系统
  • 黑马头条--day01.环境搭建
  • 流量分析基础
  • 【MySQL】启动 和 连接 MySQL
  • Docker构建镜像时空间不足:/var/lib/docker,no space left on device
  • 智能优化算法应用:基于引力搜索算法3D无线传感器网络(WSN)覆盖优化 - 附代码
  • QT----第三天,Visio stdio自定义封装控件,鼠标事件,定时器,事件分发器过滤器,绘图事件
  • K8s投射数据卷
  • 【Docker】离线一键式安装docker、docker-compose
  • Java EE 多线程之 JUC
  • 微信小程序(二) ——模版语法1
  • 在MFC(Microsoft Foundation Classes)中 CreateThread函数
  • 用docker创建jmeter容器,如何实现性能测试?
  • AE-制作绚丽的图形通道
  • C语言——谁考了第k名(头歌编程刷题)
  • ----------
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • CEF与代理
  • Dubbo 整合 Pinpoint 做分布式服务请求跟踪
  • export和import的用法总结
  • fetch 从初识到应用
  • Git 使用集
  • gulp 教程
  • JavaScript/HTML5图表开发工具JavaScript Charts v3.19.6发布【附下载】
  • JavaScript对象详解
  • java第三方包学习之lombok
  • mongo索引构建
  • OpenStack安装流程(juno版)- 添加网络服务(neutron)- controller节点
  • php中curl和soap方式请求服务超时问题
  • session共享问题解决方案
  • Vue组件定义
  • 成为一名优秀的Developer的书单
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 第2章 网络文档
  • 和 || 运算
  • 记一次用 NodeJs 实现模拟登录的思路
  • 警报:线上事故之CountDownLatch的威力
  • 力扣(LeetCode)56
  • 山寨一个 Promise
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 微信如何实现自动跳转到用其他浏览器打开指定页面下载APP
  • - 转 Ext2.0 form使用实例
  • nb
  • ​iOS安全加固方法及实现
  • ​linux启动进程的方式
  • ​如何使用ArcGIS Pro制作渐变河流效果
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (LNMP) How To Install Linux, nginx, MySQL, PHP
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)为C# Windows服务添加安装程序
  • .MyFile@waifu.club.wis.mkp勒索病毒数据怎么处理|数据解密恢复
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .NET delegate 委托 、 Event 事件,接口回调