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. 卫星视频目标分割ÿ…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...
TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
C++实现分布式网络通信框架RPC(2)——rpc发布端
有了上篇文章的项目的基本知识的了解,现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...
