NextJs - 服务端/客户端组件之架构多样性设计
NextJs - 服务端/客户端组件之架构多样性设计
- 前言
- 一. 架构设计
- 1.1 SSR+流式渲染常见错误设计之 - 根页面同步阻塞
- 1.2 架构设计之 - 客户端组件依赖于服务端组件数据
- ① 使用 Redux 完成数据共享
- 1.3 架构设计之 - 单页内的分步骤跳转
- ① 如何做到服务端组件和客户端组件之间的切换
- ② 进行UI切换的时候如何做到状态保持
前言
本篇文章主要讲解不同场景下,我们怎样去设计客户端和服务端组件的交互,或者是怎么去写代码。本篇文章建立于:使用SSR
渲染+Suspense
流式渲染,并且服务端/客户端组件混合使用的基础上讲解的。
一. 架构设计
我们知道,NextJs
的APP
路由模式下,在对应目录下创建一个page.tsx
文件,他就会生成对应的路由,我们可以称page.tsx
为根页面。
在此基础上,我们说下基本准则:
- 根页面(
page.tsx
)一般作为服务端组件,我们常用于获取一些上下文变量。 - 切记不可让根页面作为同步请求获取数据的地方,否则整个页面就会同步阻塞,等待请求返回才能开始渲染。
我们接下来先做个简单的讲解。
1.1 SSR+流式渲染常见错误设计之 - 根页面同步阻塞
在刚开始接触Nextjs
这类具备SSR
渲染的框架的时候,可能容易写出这样的代码:
- 我们在
page.tsx
根页面中同步阻塞获取接口数据,然后将数据通过Props
的形式传递给子组件 - 子组件可能是服务端组件、客户端组件。如图:
这种写法,从逻辑上它并没有任何问题,但是在Suspense
流式渲染的场景下,就没有任何意义。因为阻塞的动作发生在服务端,也就是说:
- 必须阻塞所有的异步接口返回,我们的服务器才会开始渲染组件。
- 哪怕我们的子组件使用
Suspense
包装,也没有任何作用。 - 我们的页面打开来就会白屏阻塞,阻塞时间取决于这个异步接口的等待返回时间。
正确设计如下:
- 我们让异步请求的逻辑,封装在一个粒度尽可能小的服务端组件中,然后使用
Suspense
包装这个服务端组件。 - 这样我们的页面,就不会因为这个请求发生阻塞。就会从上到下,依次渲染相关的组件,而使用
Suspense
包装的,就会返回对应的fallback
效果。
倘若在此基础上,我们的客户端组件,需要用到服务端组件中获取的数据,怎么交互?
1.2 架构设计之 - 客户端组件依赖于服务端组件数据
在上述架构图中,我们可以发现,我们的服务端组件是和客户端组件同一层级的。那么同一层级的就无法采用Props
的方式传递数据。
那么就可能有读者想:那如果我的客户端组件封装到服务端组件中不就好啦?如图:
如果这么做:我们的客户端组件就会随着服务端组件同时具备Suspense
效果,也就是客户端组件必须等待异步请求返回后才能完成渲染。 但是这样的设计是不合理的,因为我们的客户端组件的渲染不应该等待数据返回再完成渲染。
大家别忘了,我们的客户端组件是可以具备State
动态效果的,也就是可以使用useState
这样的勾子函数。因此我们可以做到立刻渲染客户端组件,让相关的数据通过State来传递,完成动态渲染。
那么我们如何做到服务端和客户端组件的数据共享呢?
① 使用 Redux 完成数据共享
我们服务端组件,拿到接口数据后,可以将它丢给一个专门的用于存储State
的客户端组件,这里我们称之为Context Compoent
。它的作用就是:
- 接收服务端传递的接口数据。
- 将接口数据保存在
Redux
中。
这么做的好处:
- 服务端组件的内部渲染,可以直接依赖于接口数据编译为
HTML
,但是切记服务端组件往往只用来做展示,不具备任何的交互(onChange
事件),同时服务端组件一般又通过Suspense
封装,可以完成loading
效果。 - 客户端组件几乎不受服务端组件影响,可以立刻完成渲染,将最基本的UI呈现给用户,而页面相关的数据来自于
Redux
。当ContextComponent
将服务端数据存储到Redux
中后,客户端组件自动完成动态渲染。
备注:这样的架构设计一般能满足大多数的开发需求,当然可能有更好的设计,这里只不过提供一种思路。
1.3 架构设计之 - 单页内的分步骤跳转
那么在这个架构设计基础上,倘若我的页面有这样的功能:
- 页面加载完毕之后,呈现第一页。
- 第一页可以点击:“下一步”,跳转到第二页(同一个
URL
) - 第二页还能够返回到:第一页。同时保持第一页的状态(例如
Checkbox
的勾选、Input
框的内容)
这个功能也就是单页内的分步骤跳转,说白了就是使用同一个URL
,但是具有多页效果。下一页的时候,上一页的状态还要保持。只不过UI呈现的是第二页。
但是想要实现单页内的分步骤跳转,有好几个问题需要解决:
- 我的首屏UI(第一页)是通过
SSR
渲染的,怎么做到下一步的时候,把第一页UI
切换到第二页的UI
?(别忘了,服务端组件是不具备State
效果的) - 如何控制
Redux
的初始化动作只做一次?
① 如何做到服务端组件和客户端组件之间的切换
1.我们在根页面下引入一个RoutePage
页面(客户端组件),然后将服务端组件通过Props
传递下去:
import ServerComponent from "./ServerComponent";
import RoutePage from "./RoutePage";const Parent = () => {return <><RoutePage slot={<ServerComponent/>}/></>
}export default Parent
RoutePage
组件专门用来做UI
切换的,也就是控制渲染第一页还是第二页,然后使用Redux
来获取全局的状态,我们用一个变量来代表当前是第几页(因为本案例只有两页,就用isServer
来表达了)
'use client';
import ClientComponent from "./ClientComponent";
import { ReactNode } from "react";const RoutePage = ({ slot }: { slot: ReactNode }) => {// 假代码const context = useRedux(testState);return <>{/* 如果当前是第一页,就渲染服务端组件,否则渲染客户端组件 */}{context.isServer ? { slot } : <ClientComponent />}</>
}export default RoutePage;
那么isServer
的初始值我们设定为true
,就做到首屏渲染服务端组件了。我们只要在客户端组件和服务端组件中维护这个State
即可完成UI
的切换。
设计结构如下:
备注:
- 服务端组件中需要引入额外的一个客户端组件,专门用来控制
State
。不能在服务端组件中控制State
哦。
② 进行UI切换的时候如何做到状态保持
试想一下,第一页首屏加载的时候,数据必定来自于服务端,服务端组件里面会引用一个ContextComponent
组件,每次渲染的时候都会初始化一遍数据。 假设这里是数据A
倘若第一页有个按钮:加载更多数据。它会发送请求,拉取更多的数据然后呈现在页面上,假设这里获取的数据是:数据B
。
那么此时第一页呈现的数据是 数据A
和 数据B
的一个并集:数据C
。那么问题来了:当我们点击下一步,呈现第二页,再次返回第一页的时候,会做什么操作?
- 第一页重新触发渲染(但是这里不会触发服务器的
SSR
渲染),此时服务端组件通过Props
传递的初始数据:数据A 还在,会重新赋值给Redux
。即导致数据A
会覆盖数据C
。 - 那么回到第一页后,之前的数据就被覆盖了,状态也就被刷掉了。
因此我们需要控制,Redux
的初始化赋值动作只执行一次。
这个就比较好解决了,我们只需要在Redux
中增加一个变量:hasLoadedSSR
一类的标识,代表我们已经SSR
渲染过一次了,在Redux
赋值的时候加个判断即可,以下是ContextComponent
伪代码:
'use client';const ContextComponent = (props)=>{const context = useRedux(testState)const dispatch = useDispatch();const {data} = props;// Redux初始化,如果没有经历过SSR,就完成初始化赋值if(!context.hasLoadedSSR){dispatch({context : {...data,// 再将标识赋值为truehasLoadedSSR: true}})}
}
这样就能防止每次UI切换的时候,初始化状态覆盖当前状态的问题了。
相关文章:

NextJs - 服务端/客户端组件之架构多样性设计
NextJs - 服务端/客户端组件之架构多样性设计 前言一. 架构设计1.1 SSR流式渲染常见错误设计之 - 根页面同步阻塞1.2 架构设计之 - 客户端组件依赖于服务端组件数据① 使用 Redux 完成数据共享 1.3 架构设计之 - 单页内的分步骤跳转① 如何做到服务端组件和客户端组件之间的切换…...
使用 Python 进行 PDF 文件加密
使用 Python 解密加密的 PDF 文件-CSDN博客定义一个名为的函数,该函数接受三个参数:输入的加密 PDF 文件路径input_pdf、输出的解密 PDF 文件路径output_pdf和密码password。https://blog.csdn.net/qq_45519030/article/details/141256661 在数字化时代…...

Spring Boot集成RabbitMQ
目录 1.RabbitMQ简介2.添加依赖3.配置RabbitMQ连接4.DirectExchange4.1 消费者4.2 生产者4.3 测试4.4 一个交换机对多个队列4.5 一个队列对多个消费者 5.FanoutExchange5.1 消费者5.2 生产者5.3 测试 6.TopicExchange6.1 消费者6.2 生产者 1.RabbitMQ简介 RabbitMQ是一个由Erl…...

OLED屏幕制造工艺流程
OLED屏幕制造工艺流程是一个复杂且精细的过程,涉及多个关键步骤以确保最终的显示效果和性能。以下是OLED屏幕制造工艺流程的主要步骤: 1. 衬底制作与准备 材料选择:OLED器件需要一个透明的导电衬底,通常使用玻璃或塑料材料。 清…...
knowLedge-VueCLI项目中环境变量的定义与使用
1. env 1.1简介 在 Vue CLI 创建的项目中,你可以通过 .env 文件来定义环境变量。Vue CLI 支持多种 .env 文件,它们根据文件名中的前缀来决定何时加载和使用这些环境变量。 以下是一些常见的 .env 文件及其用途: .env:在任何环境…...

【C#】 接口 继承
简介 继承是面向对象编程的核心特性之一,它允许我们创建一个类(称为子类)来继承另一个类(称为基类)的属性和方法。 作用 这样,我们可以重用代码,减少重复,并使我们的代码更加模块…...

Self-Supervised Learning(李宏毅老师系列)
自学参考: BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding BERT 论文逐段精读 视频课 课件资料 笔记 一、概述 自监督学习模型与芝麻街~ 参数量 ELMO:94MBERT:340MGPT-2:1542MMegatron&…...

8月16日笔记
只有DNS协议出网场景 DNS 协议是一种请求、应答协议,也是一种可用于应用层的隧道技术。DNS 隧道的工作原理很简单,在进行 DNS 查询时,如果查询的域名不在 DNS 服务器本机缓存中,就会访问互联网进行查询,然后返回结果。…...
苹果Mac电脑——装macOS和Windows双系统的方法
一、实验环境 在Windows系统电脑上制作MacOS启动U盘。准备一个大于16G的U盘。 二、实验步骤 2.1 在Windows系统电脑上制作MacOS启动U盘 MacOS镜像下载 在Windows系统电脑上制作MacOS启动U盘的方法 2.2 U盘插上苹果电脑,安装macOS系统 U盘插上苹果电脑…...

【C++ 面试 - 基础题】每日 3 题(十五)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/fYaBd 📚专栏简介:在这个专栏中,我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏&…...

数学建模学习笔记
数学建模学习笔记 现学现卖,随缘更新QwQ 主要根据b站大师兄的视频整理而成,有不懂的可以去看原视频 List 数学建模学习笔记一、 层次分析法1.1 矩阵的一致性及其检验1.2 权重计算1.3 具体流程 二、模糊综合评测2.1 隶属函数2.2 隶属函数的确定方法2.3 模…...

个人可识别信息(PII) AI 去除 API 数据接口
个人可识别信息(PII) AI 去除 API 数据接口 ai / 隐私保护 基于 AI 模型自动去除个人识别信息(PII) 个人信息保护 / AI 模型 。 1. 产品功能 基于自有专业模型进行 PII 自动去除高效处理敏感信息全接口支持 HTTPS(TLS v1.0 / v1.1 / v1.2 /…...
【Python-办公自动化】1秒提取PPT文本内容形成目录保存至WORD
欢迎来到"花花 Show Python",一名热爱编程和分享知识的技术博主。在这里,我将与您一同探索Python的奥秘,分享编程技巧、项目实践和学习心得。无论您是编程新手还是资深开发者,都能在这里找到有价值的信息和灵感。 自我介绍: 我热衷于将复杂的技术概念以简单易懂…...

maven介绍与安装
一. maven概述 1. 关于项目依赖的jar包管理 问题描述: 直接在每个项目的lib文件夹中复制jar包会导致多个问题,包括jar包的重复存放、版本冲突以及手动管理带来的不便和错误。 问题分析: 重复存放:每个项目都保存一份相同的jar…...

瑞友科技项目经理认证负责人杨文娟受邀为第四届中国项目经理大会演讲嘉宾︱PMO评论
全国项目经理专业人士年度盛会 北京瑞友科技股份有限公司项目经理认证负责人杨文娟女士受邀为PMO评论主办的全国项目经理专业人士年度盛会——2024第四届中国项目经理大会演讲嘉宾,演讲议题为“瑞友科技项目经理人才培养体系落地实践”。大会将于10月26-27日在北京举…...
Ubuntu基础使用
Ubuntu是一种流行的Linux操作系统。它提供了一个友好的图形界面和许多强大的功能,适用于个人电脑和服务器。一般来说使用Ubuntu都是在虚拟机上运行的。 一、虚拟机的安装 VMware是一家专门提供虚拟化解决方案的公司,而VMware Workstation是该公司开发的…...

知识图谱结构的提示
文章介绍了一种名为“知识图谱结构作为提示”(KG Structure as Prompt)的新方法,该方法旨在增强小型语言模型(SLMs)在知识驱动的因果发现任务中的能力。通过将知识图谱中的结构信息融入到基于提示的学习中,…...

(计算机网络)网络层
目录 一.网络层提供哪种服务 二.两种服务的比较 三.ip协议 四.ip地址 五.ip地址的分类 六.子网掩码 七.路由器介绍 一.网络层提供哪种服务 1.ip地址--唯一的标识互联网上的某一台主机 2. 虚电路:虚拟的电路 二.两种服务的比较 ip数据报,不需要建…...

[upload]-[GXYCTF2019]BabyUpload1-笔记
尝试上传.htaccess和图片和一句话木马提示 php文件提示 响应头可以看到 构造一句话图片木马如下: <script languagephp>eval($_POST[cmd]);</script> 上传成功 必须增加文件夹下jpg后缀解析php .htaccess如下 <FilesMatch "jpg">Set…...

2023卫星视频综述论文Recent Advances in Intelligent Processing of Satellite Video
2023卫星视频综述论文Recent Advances in Intelligent Processing of Satellite Video 1.摘要2.引言3. 文章的定量分析4 难点与挑战5 方法论系统A. 卫星视频观察的特点B. 卫星视频目标跟踪与运动估计C. 卫星视频目标检测D. 卫星视频超分辨率 (VSR)E. 卫星视频目标分割ÿ…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...