Nextjs 的客户端渲染和服务端渲染

发布于: 2025-06-29 · 10 min read · 更新于: 2025-06-29
Nextjs全栈

Next.js 的出现及 React 的服务端组件, 模糊了前后端的界限. 以前熟悉的前后端分离模式: 后端去数据库取数据, 前端负责渲染的模式被彻底打破. 仿佛又回到前后端一体的状态

但其实, Nextjs 通过巧妙的 use client 关键字, 将服务端与客户端渲染严格区分出来.

其中很多细节点, 还是值得研究的. 比如最近我在重构我这个博客的源码, 深有体会. 下面将我碰到的重构中的问题记录下来.

Client Component

不讲名词定义和道理, 这里只摆出我们以前熟悉的 React 组件的一个小 demo :

1export default function PostPage({ params }: { params: Promise<{ slug: string }> }) {
2  const router = useRouter(); // ❌ 客户端 API
3  const [post, setPost] = useState(null); // ❌ React hooks
4  const [loading, setLoading] = useState(true); // ❌ React hooks
5  
6  useEffect(() => { // ❌ React hooks
7    const fetchPost = async () => {
8      // 数据获取逻辑
9    };
10    fetchPost();
11  }, []);
12  
13  // 其他客户端逻辑...
14}

可以明确, 以上的诸如 useState, useEffect 等api, 均是react 的核心成员, 在 Nextjs 及服务端组件出现之前, 他们都是由前端渲染的.

而在 Nextjs 出现之后, 这一切如果还想写在项目里, 我们必须在文件的顶部加上use client 关键字, 因为服务端的 node 不会理解 React 里的关键字

1'use client';
2
3export default function PostPage({ params }: { params: Promise<{ slug: string }> }) {
4 // 其他客户端逻辑...
5}

Server Component

默认的 .ts 或者 .tsx 文件, 在 Nextjs 里是不需要标注的, 他会先调用调用服务端 node 进行渲染. 再看看官方的原话:

By default, layouts and pages are Server Components, which lets you fetch data and render parts of your UI on the server, optionally cache the result, and stream it to the client. When you need interactivity or browser APIs, you can use Client Components to layer in functionality.

以上是官方的原话, 服务端组件的作用是 fetch data and render parts of your UI on the server, 除了获取数据, 还有部分 UI 渲染.

这里开始, 就有点混乱了, 服务端组件除了获取数据, 还可以渲染 UI, 并且将其缓存, stream 到客户端. 于是我们再继续看文档

  • Use Client Components when you need:
    • State and event handlers. E.g. onClick, onChange.
    • Lifecycle logic. E.g. useEffect.
    • Browser-only APIs. E.g. localStorage, window, Navigator.geolocation, etc.
    • Custom hooks.

到这里, 我们基本明确了, 如果一函数组件, 假如有一个地方混进来诸如, 我将其归为 3 类:

  1. onClick onChange 等键盘事件
  2. localStorage window 这样的浏览器对象
  3. useEffect useState Custom hooks 这样的 react 客户端函数

则整个函数都必须标注为 use Client. 除却上面的陈述, 其余的函数在 Nextjs 里都可以视为服务端函数(或组件).

上述的 1, 2点都很好理解, 第3点就有点模糊了, 因为 React 和 Nextjs 的API 众多 哪些API 必须为客户端渲染? 哪些又两者都可以?

精确区分服务端和客户端渲染

我这里将其列了一个表格

渲染环境React 函数/API说明
服务器端React.createElement()基础 React API
服务器端React.Fragment基础 React API
服务器端React.Suspense基础 React API
服务器端React.lazy()用于代码分割
服务器端async/await 组件函数服务器组件专用
服务器端直接的数据获取(fetch, await supabase.from() 等)服务器组件专用
服务器端notFound()Next.js 专用
服务器端redirect()Next.js 专用
服务器端getStaticProps()Pages Router 静态渲染
服务器端getStaticPaths()Pages Router 静态渲染
服务器端generateStaticParams()App Router 静态渲染
客户端useState()React Hooks
客户端useEffect()React Hooks
客户端useCallback()React Hooks
客户端useMemo()React Hooks
客户端useRef()React Hooks
客户端useContext()React Hooks
客户端useReducer()React Hooks
客户端useLayoutEffect()React Hooks
客户端useImperativeHandle()React Hooks
客户端useDebugValue()React Hooks
客户端useId()React Hooks
客户端useTransition()React Hooks
客户端useDeferredValue()React Hooks
客户端useSyncExternalStore()React Hooks
客户端useInsertionEffect()React Hooks
客户端useRouter()Next.js 客户端 Hooks
客户端usePathname()Next.js 客户端 Hooks
客户端useSearchParams()Next.js 客户端 Hooks
客户端useParams()Next.js 客户端 Hooks
客户端window 对象浏览器 API
客户端document 对象浏览器 API
客户端localStorage / sessionStorage浏览器 API
客户端navigator 对象浏览器 API
客户端事件监听器 (addEventListener)浏览器 API
客户端需要 DOM 操作的库第三方库的客户端功能
客户端需要浏览器 API 的库第三方库的客户端功能
客户端动画库 (Framer Motion, React Spring 等)第三方库的客户端功能

评论区