RSC与流式渲染,为什么要用和怎么用

一、CSR,SSR,RSC的对比

传统的SSR需要服务器拿到所有数据后返回html文件,而流式渲染下服务器返回的是一个html流,服务器可以快速地将内容呈现给用户,而不是白屏干等。

下面这张图可以更直观感受两者区别:

文章参考 bobi.ink/2023/06/05/...

二、使用RSC的注意事项

  1. 因为传统的SSR心智负担就比CSR应用大上很多,因为你要考虑这段代码是会跑在服务器端还是浏览器端还是两端都会执行。而流式渲染SSR在心智负担上比传统SSR更大,因为server component 是不允许增加交互逻辑的。参考 nextjs.org/docs/app/bu...
  2. client componet和server componet都会在服务端渲染
  3. client componet一定要保证服务端和客户端渲染的内容一致的,所以尽量不要使用isInBrowser此类的api去区分渲染。
  4. 如果有些只想在客户端引入,那么使用dynamic动态引入一个组件,但是这种引入会增加一个chunkjs的加载。自行斟酌
  5. npm run build的时候会执行页面的代码,如果页面中使用了服务端才有的依赖或者req,编译态都没有这些,取值的时候需要做写法兼容

三、使用RSC的场景

适合的业务场景

  1. 数据密集型应用:RSC允许在服务器上渲染组件,这可以减少客户端的 JavaScript 大小和执行时间,对于数据密集型应用(如后台表单页、表格列表页等)非常有用。
  2. 需要快速首屏渲染的应用:RSC和流式渲染的目标是提高首屏渲染的速度,而不是降低它。这是通过在服务器端进行更多的工作(如数据获取和组件渲染),并尽早将结果发送到客户端来实现的。 在传统的客户端渲染模型中,浏览器需要下载、解析和执行 JavaScript,然后 JavaScript 会获取数据并渲染组件。这个过程可能会导致首屏渲染变慢,特别是在网络或设备性能较差的情况下。 使用 RSC 和流式渲染,服务器可以在发送 HTML 到浏览器之前获取数据和渲染组件。这意味着浏览器可以更早地开始显示内容,而不需要等待所有的 JavaScript 和数据都准备好。 然而,如果服务器端的数据获取或渲染时间过长,那么这可能会影响首屏渲染的速度。为了解决这个问题,你可以使用各种优化技术,如数据预加载、缓存、代码拆分等。 总的来说,RSC 和流式渲染是否会导致首屏渲染变慢,取决于许多因素,包括服务器的性能、网络条件、数据获取的速度、应用的复杂性等。在大多数情况下,它们都可以提高首屏渲染的速度。

不适合的业务场景

  1. 需要大量客户端交互的应用:如果需要大量的客户端交互,那么使用 RSC 可能不是最佳选择,因为 RSC 主要用于渲染不需要客户端交互的组件。
  2. 需要完全控制渲染过程的应用:如果需要完全控制渲染过程,那么流式渲染可能不适合,因为流式渲染会在数据到达时立即发送 HTML 到浏览器,这可能会导致失去对渲染过程的一些控制。

四、如何next里使用RSC

由于RSC是服务端渲染的,不会在客户端运行,因此他们不能直接处理客户端时间,如onClick。

如果需要处理客户端事件,那么可以采用RSC+客户端组件的混合模式。

首先,开启next的App Router模式:Upgrading: App Router Migration | Next.js (nextjs.org)

RSC

typescript 复制代码
function sleep(time: number) {
  return new Promise((resolve) => {
    setTimeout(resolve, time);
  });
}
async function getContent() {
  await sleep(1000);
  return { configs: 'ServerComponent' };
}

export default async function ServerComponent() {
  const content = await getContent();

  return (
    <div>
      {JSON.stringify(content.configs)}
      <br />
    </div>
  );
}

RSC+SSR客户端组件

rsc负责数据,客户端组件负责交互

typescript 复制代码
//RSC

import ClientComponentInServerComponent from './ClientComponentInServerComponent';

function sleep(time: number) {
  return new Promise((resolve) => {
    setTimeout(resolve, time);
  });
}
async function getContent() {
  await sleep(1000);
  return {
    configs: 'ServerComponent',
    data: [
      { id: 1, name: 'data1' },
      { id: 2, name: 'data2' },
      { id: 3, name: 'data3' },
      { id: 4, name: 'data4' },
    ],
  };
}

export default async function ServerComponent() {
  const content = await getContent();

  return (
    <div>
      {JSON.stringify(content.configs)}
      <ClientComponentInServerComponent data={content.data} />
      <br />
    </div>
  );
}

typescript 复制代码
// 客户端组件
'use client';

interface DataItemType {
  id: number;
  name: string;
}

function ClientComponentInServerComponent({ data }: { data: DataItemType[] }) {
  console.log(data, 'data');
  const handleClick = (item: DataItemType) => {
    console.log('Clicked item:', item);
  };

  return (
    <ul>
      {data.map((item) => (
        <li key={item.id} onClick={() => handleClick?.(item)}>
          <div> {item.name}</div>
        </li>
      ))}
    </ul>
  );
}

export default ClientComponentInServerComponent;
相关推荐
xyphf_和派孔明20 分钟前
企业级微前端项目完整创建步骤,第三步:配置 Vue 子应用
前端·javascript
自强的小白21 分钟前
条件查询或查询全部时时前端请求数据等时间格式
前端
阳光是sunny39 分钟前
LangGraph实战教程:一文搞懂图的状态(State)管理
前端·人工智能·后端
whyfail1 小时前
前端学 Spring Boot(5):从“你是谁”到“服务真的上线了”
前端·spring boot·后端
程序员黑豆1 小时前
鸿蒙开发:RelativeContainer相对布局组件实战——实现5个文本组件对齐
前端·华为·harmonyos
环境栈笔记2 小时前
高性价比指纹浏览器推荐与选型:如何对照价格和实际可用功能筛选候选
前端·人工智能·后端·自动化
hyf3266332 小时前
泛程序哪有想象中难!小白跟着走一遍就全懂
前端·爬虫·搜索引擎·seo·蜘蛛池
码农学院2 小时前
React公众号开发:母婴用品会员积分体系技术方案
前端·react.js·前端框架
路光.2 小时前
Vue2升级Vue3处理原 UMD/CommonJS 打包文件,不是标准 ESM
前端·javascript·vue.js·vue3
黄华SJ520it3 小时前
门店预约系统开发:提升服务行业数字化转型
前端·数据库·系统开发