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

news2024/12/23 17:49:41

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">
            <div
              className="animate-pulse h-7 w-1/2 bg-slate-200 rounded duration-1000"
              style={{
                animationDelay: `${i * 0.05}s`,
              }}
            ></div>
            <div
              className="animate-pulse h-5 w-full bg-slate-200 rounded duration-1000"
              style={{
                animationDelay: `${i * 0.05}s`,
              }}
            ></div>
            <div
              className="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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1317133.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【深度学习】注意力机制(六)

本文介绍一些注意力机制的实现&#xff0c;包括MobileVITv1/MobileVITv2/DAT/CrossFormer/MOA。 【深度学习】注意力机制&#xff08;一&#xff09; 【深度学习】注意力机制&#xff08;二&#xff09; 【深度学习】注意力机制&#xff08;三&#xff09; 【深度学习】注意…

【从零开始学习JVM | 第九篇】了解 常见垃圾回收器

前言&#xff1a; 垃圾回收器&#xff08;Garbage Collector&#xff09;是现代编程语言中的一项重要技术&#xff0c;它提供了自动内存管理的机制&#xff0c;极大地简化了开发人员对内存分配和释放的繁琐工作。通过垃圾回收器&#xff0c;我们能够更高效地利用计算机的内存资…

MetaAI发布Seamless:两秒内实现跨语言同声传译

在当今日益互联的世界中&#xff0c;语言差异常常成为沟通的障碍。MetaAI最新发布的语音翻译大模型Seamless&#xff0c;正是为打破这一障碍而生。Seamless不仅提供流畅、高效的多语言翻译功能&#xff0c;更在保留说话人韵律和风格方面取得突破&#xff0c;是AI同声传译领域的…

Python开源项目周排行 2023年第40周

Python 趋势周报&#xff0c;按周浏览往期 GitHub,Gitee 等最热门的Python开源项目&#xff0c;入选的项目主要参考GitHub Trending,部分参考了Gitee和其他。排名不分先后&#xff0c;都是当周相对热门的项目。 入选公式&#xff1d;70%GitHub Trending20%Gitee10%其他 关注微…

Tekton 构建容器镜像

Tekton 构建容器镜像 介绍如何使用 Tektonhub 官方 kaniko task 构建docker镜像&#xff0c;并推送到远程dockerhub镜像仓库。 kaniko task yaml文件下载地址&#xff1a;https://hub.tekton.dev/tekton/task/kaniko 查看kaniko task yaml内容&#xff1a; 点击Install&…

QQ邮箱发送工具类的实现

我们在日常开发中&#xff0c;需要实现一个对邮箱的发送&#xff0c;今天就实现邮箱的发送工具类&#xff0c;只需要一些注册邮箱之后的配置即可&#xff0c;我这边使用的是qq邮箱 0.加上依赖 <!--邮箱--><dependency><groupId>org.springframework.boot&l…

Docker单机部署OceanBase

文章目录 说明机器软硬件要求指导文档本次部署环境说明 OceanBase单机部署&#xff08;Docker&#xff09;一&#xff1a;拉取 OceanBase 数据库相关镜像二&#xff1a;启动 OceanBase 数据库实例完整启动日志展示 三&#xff1a;连接实例遇到报错&#xff1a;没有mysql客户端 …

【lesson14】MySQL表的基本查询retrieve(读取)1

文章目录 表的基本操作介绍retrieveselect列建表基本测试 where子句建表基本测试 表的基本操作介绍 CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#xff0c;Delete&#xff08;删除&#xff09; retrieve select列 建表 基本测试 插入数据 全列查询 …

GoogLeNet(pytorch)

亮点与创新&#xff1a; 1. 引入Inception基础结构 2. 引入PW维度变换卷积&#xff0c;启迪后续参数量的优化 3. 丢弃全连接层&#xff0c;使用平均池化层&#xff08;大大减少模型参数&#xff09; 4. 添加两个辅助分类器帮助训练&#xff08;避免梯度消失&#xff0c;用于…

智能电气柜环境监测系统

智能电气柜环境监控系统是一种基于传感器技术和物联网技术的智能化监控系统&#xff0c;用于对电气柜内的环境参数进行实时监测和管理。依托智慧电力运维工具-电易云&#xff0c;通过安装在电气柜内的多个传感器&#xff0c;实时采集电气柜内的温度、湿度、氧气浓度、烟雾等关键…

windows redis 允许远程访问配置

安装好windows版本的redis&#xff0c;会以服务方式启动&#xff0c;但是不能远程访问&#xff0c;这个时候需要修改配置。redis安装路径下会有2个配置文件&#xff0c;究竟需要怎么修改才能生效呢&#xff1f;看下图 这里的redis服务指定了是redis.windows-service.conf文件&…

java_web_电商项目

java_web_电商项目 1.登录界面2.注册界面3. 主界面4.分页界面5.商品详情界面6. 购物车界面7.确认订单界面8.个人中心界面9.收货地址界面10.用户信息界面11.用户余额充值界面12.后台首页13.后台商品增加14.后台用户增加15.用户管理16.源码分享1.登录页面的源码2.我们的主界面 1.…

Xml与Json格式在线转换器

具体请前往&#xff1a;在线Json转Form表单参数工具

计算机网络(四)

九、网络安全 &#xff08;一&#xff09;什么是网络安全&#xff1f; A、网络安全状况 分布式反射攻击逐渐成为拒绝攻击的重要形式 涉及重要行业和政府部门的高危漏洞事件增多。 基础应用和通用软硬件漏洞风险凸显&#xff08;“心脏出血”&#xff0c;“破壳”等&#x…

springMVC-@RequestMapping

基本介绍 RequestMapping注解可以指定控制器/处理器的某个方法的请求的url, 示例 &#xff08;结合springMVC基本原理理解&#xff09; Controller public class UserHandler {RequestMapping(value "/login")public String login() {System.out.println("登…

JOSEF约瑟 静态双位置继电器 DPR-35 DC110V柜内固定安装,板前接线

系列型号&#xff1a; DPR-20双位置继电器&#xff1b;DPR-31双位置继电器&#xff1b; DPR-32双位置继电器&#xff1b;DPR-33双位置继电器&#xff1b; DPR-34双位置继电器&#xff1b;DPR-35双位置继电器&#xff1b; DPR-11双位置继电器&#xff1b;DPR-12双位置继电器…

【数据结构和算法】--队列的特殊结构-循环队列

目录 循环队列的结构循环队列的实现循环队列的创建循环队列为空判断循环队列为满判断入队出队返回循环队列首元素返回循环队列尾元素释放循环队列 循环队列的结构 循环队列是队列的一种特殊结构&#xff0c;它的长度是固定的k&#xff0c;同样是先进先出&#xff0c;理论结构是…

飞天使-docker知识点6-容器dockerfile各项名词解释

文章目录 docker的小技巧dockerfile容器为什么会出现启动了不暂停查看docker 网桥相关信息 docker 数据卷 docker的小技巧 [rootlight-test playbook-vars[]# docker inspect -f "{{.NetworkSettings.IPAddress}}" d3a9ae03ae5f 172.17.0.4docker d3a9ae03ae5f:/etc…

RK3399平台开发系列讲解(内核入门篇)什么是函数调用栈

🚀返回专栏总目录 文章目录 一、什么是函数调用栈二、函数调用栈解析三、什么是stack overflow沉淀、分享、成长,让自己和他人都能有所收获!😄 📢在开发软件的过程中我们经常会遇到错误,如果你用 Google 搜过出错信息,那你多少应该都访问过Stack Overflow这个网站。作…