在客户端组件中使用服务器组件

profile image

在Next.js中,所有组件默认都是服务器组件。让我们探索如何在客户端组件中使用它们。

本帖由 DeepL 翻译。如有任何翻译错误,请告知我们!

理解服务器/客户端组件

在Next.js App Router中,所有组件默认都是服务器组件。 然而,有时你需要客户端功能(例如useState、onClick等)。在这种情况下应该怎么做?

要使用客户端组件,请在文件顶部添加'use client'指令。

jsx
'use client'

export const ClientComponent = () => {
 return (
   <div>
     <h1>Client Component</h1>
   </div>
 );
};

这会从该组件创建一个客户端边界,组件中导入的所有组件和模块文件都在客户端运行。 (这里重要的不是组件的渲染层次结构,而是导入关系。)

因此,没有'use client'的组件也会自动转换为客户端组件。

这种情况怎么样?让我们在客户端组件内声明一个服务器组件。

jsx
import React from 'react';

export const ServerComponent = async () => {
  const data = await getData();
  return <div>{JSON.stringify(data)}</div>;
};

async function getData() {
  const res = await fetch('https://jsonplaceholder.typicode.com/todos/1');
  const json = await res.json();

  if (!res.ok) {
    throw new Error('Failed to fetch data');
  }

  return json;
}

export default ServerComponent;
jsx
'use client'

import ServerComponent from './ServerComponent'

export const ClientComponent = () => {
  return (
    <div>
      <h1>Client Component</h1>
      <ServerComponent />
    </div>
  )
}

你会看到带有以下警告的错误日志: img01.png

当同时使用客户端组件和服务器组件时,有重要的规则:

  • ✅ 服务器组件下的客户端组件(可行)
  • ✅ 客户端组件下的客户端组件(可行)
  • ❌ 客户端组件下的服务器组件(不可行)

🔧 解决方案:使用Props模式

那么如何在客户端组件内使用服务器组件?答案很简单:通过props传递。

jsx
// 有效的模式
'use client'
export const ClientComponent = ({ children }) => {
  return (
    <div>
      <h1>Client Component</h1>
      {children}
    </div>
  );
};

const App = () => {
  return (
    <ClientComponent>
      <ServerComponent />
    </ClientComponent>
  )
}

为什么它这样工作?

关键是客户端边界由导入位置决定,而不是组件的父子关系。 在上面的例子中,ServerComponent由App导入,App是一个服务器组件,所以它保持为服务器组件。

ClientComponent只知道在哪里渲染它作为props接收的children,但不知道会有什么组件。 这种模式允许你使用服务器组件,即使它们被Layout中用use client声明的providers包裹。

深入探讨

服务器组件的运行方式与传统的服务器端渲染(SSR)完全不同。 与SSR在服务器上生成完整HTML不同,服务器组件生成一种称为React Server Components(RSC)Payload的特殊JSON类流。 img02.png

这个RSC Payload包括组件树结构、数据、HTML内容等,服务器将基本数据类型如字符串、数字、数组和内置对象如React元素、Date对象、Map、Set等序列化,以包含在这个payload中。 另一方面,函数、类实例、闭包和事件监听器等不能被序列化。

因此,你不能从服务器组件向客户端组件传递不能序列化的值作为props

在渲染服务器组件时,如果遇到客户端组件,该部分会被标记为特殊的占位符。 这个占位符包括客户端组件的引用和props信息,允许客户端准确地渲染该组件。

客户端将从服务器接收的RSC payload转换为React可以理解的形式,并对从服务器接收的内容进行hydration。 此时,在标记为占位符的部分渲染相应的客户端组件。


参考

❤️ 0
🔥 0
😎 0
⭐️ 0
🆒 0