【Next.js】如何在页面上区分服务端组件还是客户端组件

495 阅读2分钟

要在页面上验证内容是否在服务器端渲染,你可以通过以下几种方式:

1、查看页面源代码(View Page Source):

  • 在浏览器中右键点击页面,选择"查看网页源代码"(View Page Source)
  • 或者使用快捷键 Ctrl + U(Windows)/ Cmd + U(Mac)
  • 在源代码中,你应该能看到完整的 HTML 内容,包括用户数据,类似这样:

image.png

而如果是客户端则没有用户数据,只有 html 代码

image.png

2、禁用 JavaScript:

禁用快捷路径: chrome://settings/content/javascript

image.png

添加网址, 刷新页面,如果内容仍然显示,说明是服务器端渲染的

3、使用网络慢速模式:

  • 在 Chrome 开发者工具中
  • 切换到 "Network" 标签
  • 在 "throttling" 下拉菜单中选择 "Slow 3G"
  • 刷新页面,你会看到内容是立即显示的,而不是等待 JavaScript 加载后才显示

4、使用 curl 命令(终端)

curl http://localhost:3000/about

这将显示服务器返回的原始 HTML,如果看到用户数据在 HTML 中,就证明是服务器端渲染的。

如果是客户端渲染,你在页面源代码中只能看到基本的 HTML 结构,不会包含用户数据,数据会在 JavaScript 执行后才显示出来。而服务器端渲染的内容会直接出现在初始 HTML 中。

demo 示例

// 客户端代码demo
"use client"

import { useState, useEffect } from 'react';

function getUsers() {
  return fetch('https://jsonplaceholder.typicode.com/users')
    .then(res => {
      if (!res.ok) {
        throw new Error('Failed to fetch users');
      }
      return res.json();
    });
}

export default function About() {
  const [users, setUsers] = useState<any[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    getUsers()
      .then(data => {
        setUsers(data);
        setLoading(false);
      })
      .catch(err => {
        setError(err.message);
        setLoading(false);
      });
  }, []);

  if (loading) {
    return <div className="p-4">Loading...</div>;
  }

  if (error) {
    return <div className="p-4 text-red-500">Error: {error}</div>;
  }
  
  return (
    <div className="p-4">
      <h1 className="text-2xl font-bold mb-4">关于我们的团队(客户端)</h1>
      <div className="grid gap-4">
        {users.map((user: any) => (
          <div key={user.id} className="border p-4 rounded-lg">
            <h2 className="text-xl font-semibold">{user.name}</h2>
            <p className="text-gray-600">{user.email}</p>
            <p className="text-gray-600">{user.company.name}</p>
          </div>
        ))}
      </div>
    </div>
  );
}
// 服务端代码
async function getUsers() {
  console.log('Fetching users from server side...'); // 这个只会在服务器端控制台显示
  const res = await fetch('https://jsonplaceholder.typicode.com/users', {
    // 强制 SSR
    cache: 'no-store'
  });
  
  if (!res.ok) {
    throw new Error('Failed to fetch users');
  }
  
  return res.json();
}



export default async function About() {
  const users = await getUsers();
  
  return (
    <div className="p-4">
      <h1 className="text-2xl font-bold mb-4">关于我们的团队(服务端)</h1>
      <div className="grid gap-4">
        {users.map((user: any) => (
          <div key={user.id} className="border p-4 rounded-lg">
            <h2 className="text-xl font-semibold">{user.name}</h2>
            <p className="text-gray-600">{user.email}</p>
            <p className="text-gray-600">{user.company.name}</p>
          </div>
        ))}
      </div>
      
    </div>
  );
}

注意事项

  1. hydration 的影响:Next.js 的客户端组件通常通过 hydration 与服务端生成的 HTML 结合。即使是客户端组件,如果页面使用了 SSR 或 SSG,源代码中可能仍有初始内容。

  2. 构建模式

    • SSG(静态生成) :所有组件(包括客户端组件的初始状态)可能在构建时生成,禁用 JS 也能看到内容。
    • SSR(服务端渲染) :内容动态生成,服务端组件占主导。
  3. 动态导入:如果客户端组件通过 dynamic 导入,禁用 JS 可能导致完全不可见。

亲测这四种方式都可以,这不我就发现自己 用 Next.js 写的博客网站不是 ssr 渲染...