一、客户端组件
在 Next.js 中,客户端组件(Client Components)是为处理动态交互和运行时 JavaScript 提供的组件类型,与服务端组件(Server Components)配合使用,可以灵活实现现代 Web 应用的需求。
客户端组件的概念
客户端组件通过文件顶部的 'use client'; 声明来标识。
客户端组件的定义
客户端组件在浏览器中运行,包含 React 的运行时 JavaScript,支持 React 的所有功能(如 useState、useEffect 等 Hook)。这些组件可以处理动态交互和浏览器特有的功能(如 DOM 操作、事件处理、地理位置和 localStorage 等等)。
'use client' //声明为客户端组件
import {useState} from 'react'
export default function Page(){
...
}
客户端组件的特点
- 运行时依赖:必须在浏览器中执行,依赖 React 的运行时。
- 支持浏览器 API:可以使用
window、document等浏览器特定的功能。 - 动态交互能力:允许使用状态管理(如
useState)和副作用(如useEffect)来处理用户交互。
二、服务端组件(React Server Components)
服务端组件的核心理念:
- 在服务器端执行组件的逻辑,将生成的UI片段(HTML)发送给客户端
- 减少客户端JS的数量,将渲染的工作移到服务器端以提升性能
与传统渲染方式的区别:
使用场景
- 静态内容: 不需要交互的页面,例如展示产品列表、博客文章或营销页面。
- 高性能需求: 需要减少客户端 JS 负载的应用,例如大型电商网站或高流量博客。
- 复杂数据逻辑: 数据需要在服务器端整合的场景,例如多数据源的聚合展示。
三、如何选择服务端组件、客户端组件?
服务端场景
-
SEO 优化:需要通过服务端渲染以提高搜索引擎优化(SEO)效果。
-
静态内容渲染:页面内容基本不需要交互或客户端状态管理,例如展示产品详情、博客文章等。
-
数据预加载:页面数据可以在服务端加载,减少客户端的计算量和加载时间。
-
性能优化:适合减少客户端负担,减少 JavaScript 执行,特别是在低性能设备上。
-
在服务端渲染,生成完整的 HTML 后发送到客户端。
-
不支持客户端状态管理,如
useState和useEffect。 -
有利于首次渲染的性能,适用于静态内容和展示。
客户端场景
-
动态交互:需要用户输入、事件处理或界面更新的页面,如表单提交、动态内容显示等。
-
客户端状态管理:需要在客户端存储和管理状态,常使用 React 的
useState和useEffect。 -
依赖浏览器特性:例如,使用浏览器 API(如
localStorage、window等)来执行任务。 -
需要局部更新的组件:只需要渲染和更新特定部分,而不是整个页面。
-
在客户端渲染,允许更复杂的交互。
-
支持客户端状态管理,使用 React Hook(
useState,useEffect等)。 -
增加初始加载负担,但提供更灵活的用户交互。
四、交替使用服务端组件和客户端组件
服务端组件可以直接导入客户端组件,但客户端组件并不能导入服务端组件。
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)不会被缓存