Next.js-----服务端组件、客户端组件

184 阅读4分钟

一、客户端组件

在 Next.js 中,客户端组件(Client Components)是为处理动态交互和运行时 JavaScript 提供的组件类型,与服务端组件(Server Components)配合使用,可以灵活实现现代 Web 应用的需求。

客户端组件的概念

客户端组件通过文件顶部的 'use client'; 声明来标识。

客户端组件的定义

客户端组件在浏览器中运行,包含 React 的运行时 JavaScript,支持 React 的所有功能(如 useStateuseEffect 等 Hook)。这些组件可以处理动态交互浏览器特有的功能(如 DOM 操作、事件处理、地理位置和 localStorage 等等)。

'use client' //声明为客户端组件

import {useState} from 'react'

export default function Page(){
  ...
}

客户端组件的特点

  • 运行时依赖:必须在浏览器中执行,依赖 React 的运行时。
  • 支持浏览器 API:可以使用 windowdocument 等浏览器特定的功能。
  • 动态交互能力:允许使用状态管理(如 useState)和副作用(如 useEffect)来处理用户交互。

二、服务端组件(React Server Components)

服务端组件的核心理念:

  • 在服务器端执行组件的逻辑,将生成的UI片段(HTML)发送给客户端
  • 减少客户端JS的数量,将渲染的工作移到服务器端以提升性能

与传统渲染方式的区别:

截屏2025-03-31 22.37.45.png

使用场景

  • 静态内容: 不需要交互的页面,例如展示产品列表、博客文章或营销页面。
  • 高性能需求: 需要减少客户端 JS 负载的应用,例如大型电商网站或高流量博客。
  • 复杂数据逻辑: 数据需要在服务器端整合的场景,例如多数据源的聚合展示。

三、如何选择服务端组件、客户端组件?

服务端场景

  • SEO 优化:需要通过服务端渲染以提高搜索引擎优化(SEO)效果。

  • 静态内容渲染:页面内容基本不需要交互或客户端状态管理,例如展示产品详情、博客文章等。

  • 数据预加载:页面数据可以在服务端加载,减少客户端的计算量和加载时间。

  • 性能优化:适合减少客户端负担,减少 JavaScript 执行,特别是在低性能设备上。

  • 在服务端渲染,生成完整的 HTML 后发送到客户端。

  • 不支持客户端状态管理,如 useState 和 useEffect

  • 有利于首次渲染的性能,适用于静态内容和展示。

客户端场景

  • 动态交互:需要用户输入、事件处理或界面更新的页面,如表单提交、动态内容显示等。

  • 客户端状态管理:需要在客户端存储和管理状态,常使用 React 的 useStateuseEffect

  • 依赖浏览器特性:例如,使用浏览器 API(如 localStoragewindow 等)来执行任务。

  • 需要局部更新的组件:只需要渲染和更新特定部分,而不是整个页面。

  • 在客户端渲染,允许更复杂的交互。

  • 支持客户端状态管理,使用 React Hook(useStateuseEffect 等)。

  • 增加初始加载负担,但提供更灵活的用户交互。

四、交替使用服务端组件和客户端组件

服务端组件可以直接导入客户端组件,但客户端组件并不能导入服务端组件。

Next.js 不支持客户端组件中使用服务端组件,但支持将服务器组件作为 Props 传递给客户端组件

客户端组件

// client-components/example.tsx

'use client'
import React from 'react'

function ClientComponentExample({
  children,
}:{
   chilfren:React.ReactNode   
}) {
  return (
    <div>{children}</div>
  )
}
export default ClientComponentExample

服务端组件

// server-components/example.tsx
import React from 'react'

async function ServerComponentExample(){
  const res = await fetch('https://json.com/todo/1')
  const data = await res.json()
  
  return(
    <div>{data.title}</div>
  )
}
export default ServerComponentExample

home文件的引入

// src/app/home/page.tsx

import React from 'react'

import ClientComponentExample from '@/components/client-components/example'
import ServerComponentExample from '@/components/server-components/example'

function HomePage(){
  return (
    <div>
      <ClientComponentExample>
        <ServerComponentExample/>
      </ClientComponentExample>
    </div>
  )
}

五、服务端组件间的数据共享

在服务端获取数据时,有可能出现多个组件共用同一个数据的情况。不需要使用React Context,也不需要使用props传递数据,可以直接在需要的组件中请求数据。因为React拓展fetch功能,添加记忆缓存功能,相同的请求和参数,返回的数据会缓存。

async function getItem(){
  // fetch函数会自动缓存结果
  const res = await fetch('https://.../item')
  return res.json()
}

// 该函数北调用两次,但只在第一次执行
const item = await getItem() // 缓存未命中

// 第二次调用可能在路由中的任何地方
const item = await getItem() //缓存命中

⚠️:缓存的限制是,仅适用于请求GET中的方法fetch,其他方法(POST、DELETE)不会被缓存