“使用客户端”指令在 Next.js 13 中如何工作
P粉044526217
P粉044526217 2023-08-26 21:55:31
[React讨论组]
<p>我正在尝试使用 Next.js 13.4 和新的 <code>app/</code> 目录来了解服务器端渲染。据我了解,默认情况下每个组件都是一个<em>服务器</em>组件(即在服务器端呈现)。</p> <p>但是,我们可以使用 <code>'use client'</code> 指令来强制将组件变成<em>客户端</em>组件。</p> <p>下面,我设置了一个简单的“Hello World”组件,首先作为服务器组件,然后作为客户端组件。在每种情况下,我都会比较页面源代码。</p> <h3><code>src/app/page.js</code>(服务器组件)</h3> <pre class="brush:php;toolbar:false;">export default function Home() { return ( &lt;main&gt; &lt;h1&gt;Hello World&lt;/h1&gt; &lt;/main&gt; ) }</pre> <p>Chrome &gt; 查看页面源代码</p> <pre class="brush:php;toolbar:false;">&lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charSet="utf-8" /&gt; &lt;title&gt;Create Next App&lt;/title&gt; &lt;meta name="description" content="Generated by create next app" /&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1" /&gt; &lt;script src="/_next/static/chunks/polyfills.js" noModule=""&gt;&lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;main&gt; &lt;h1&gt;Hello World&lt;/h1&gt; &lt;/main&gt; &lt;script src="/_next/static/chunks/webpack.js" async=""&gt;&lt;/script&gt; &lt;script src="/_next/static/chunks/main-app.js" async=""&gt;&lt;/script&gt; &lt;script&gt;(self.__next_f = self.__next_f || []).push([0])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "0:"$L1"n"])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "2:I{"id":"(app-client)/./node_modules/next/dist/client/components/app-router.js","chunks":["webpack:static/chunks/webpack.js"],"name":"","async":false}n4:I{"id":"(app-client)/./node_modules/next/dist/client/components/error-boundary.js","chunks":["webpack:static/chunks/webpack.js"],"name":"","async":false}n6:I{"id":"(app-client)/./node_modules/next/dist/client/components/layout-router.js","chunks":["app-client-internals:static/chunks/app-client-internals.js"],"name":"","async":false}n7:I{"id":"(app-client)/"])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "./node_modules/next/dist/client/components/render-from-template-context.js","chunks":["app-client-internals:static/chunks/app-client-internals.js"],"name":"","async":false}n"])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "1:[[],["$","$L2",null,{"assetPrefix":"","initialCanonicalUrl":"/","initialTree":["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],"initialHead":["$L3",null],"globalErrorComponent":"$4","notFound":["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$L5","$undefined",[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]]}]}],"asNotFound":false,"children":[["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L6",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","loading":"$undefined","loadingStyles":"$undefined","hasLoading":false,"template":["$","$L7",null,{}],"templateStyles":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined","childProp":{"current":[["$","main",null,{"children":["$","h1",null,{"children":"Hello World"}]}],null],"segment":"__PAGE__"},"styles":[]}]}]}],null]}]]n"])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "5:[[["$","meta",null,{"charSet":"utf-8"}],null,null,null,null,null,null,null,null,null,null,["$","meta",null,{"name":"viewport","content":"width=device-width, initial-scale=1"}],null,null,null,null,null,null,null,null,null,null,[]],[null,null,null,null],null,null,[null,null,null,null,null],null,null,null,null,null]n3:[[["$","meta",null,{"charSet":"utf-8"}],["$","title",null,{"children":"Create Next App"}],["$","meta",null,{"name":"description","content":"Generated by create next app"}],null,null,null,null,n"])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "ull,null,null,null,["$","meta",null,{"name":"viewport","content":"width=device-width, initial-scale=1"}],null,null,null,null,null,null,null,null,null,null,[]],[null,null,null,null],null,null,[null,null,null,null,null],null,null,null,null,null]n"])&lt;/script&gt; &lt;/body&gt; &lt;/html&gt;</pre> <h3><code>src/app/page.js</code>(客户端组件)</h3> <pre class="brush:php;toolbar:false;">'use client'; export default function Home() { return ( &lt;main&gt; &lt;h1&gt;Hello World&lt;/h1&gt; &lt;/main&gt; ) }</pre> <p>Chrome &gt; 查看页面源代码</p> <pre class="brush:php;toolbar:false;">&lt;!DOCTYPE html&gt; &lt;html lang="en"&gt; &lt;head&gt; &lt;meta charSet="utf-8" /&gt; &lt;title&gt;Create Next App&lt;/title&gt; &lt;meta name="description" content="Generated by create next app" /&gt; &lt;meta name="viewport" content="width=device-width, initial-scale=1" /&gt; &lt;script src="/_next/static/chunks/polyfills.js" noModule=""&gt;&lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;main&gt; &lt;h1&gt;Hello World&lt;/h1&gt; &lt;/main&gt; &lt;script src="/_next/static/chunks/webpack.js" async=""&gt;&lt;/script&gt; &lt;script src="/_next/static/chunks/main-app.js" async=""&gt;&lt;/script&gt; &lt;script&gt;(self.__next_f = self.__next_f || []).push([0])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "0:"$L1"n"])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "2:I{"id":"(app-client)/./node_modules/next/dist/client/components/app-router.js","chunks":["webpack:static/chunks/webpack.js"],"name":"","async":false}n4:I{"id":"(app-client)/./node_modules/next/dist/client/components/error-boundary.js","chunks":["webpack:static/chunks/webpack.js"],"name":"","async":false}n6:I{"id":"(app-client)/./node_modules/next/dist/client/components/layout-router.js","chunks":["app-client-internals:static/chunks/app-client-internals.js"],"name":"","async":false}n7:I{"id":"(app-client)/"])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "./node_modules/next/dist/client/components/render-from-template-context.js","chunks":["app-client-internals:static/chunks/app-client-internals.js"],"name":"","async":false}n8:I{"id":"(app-client)/./src/app/page.js","chunks":["app/page:static/chunks/app/page.js"],"name":"","async":false}n"])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "1:[[],["$","$L2",null,{"assetPrefix":"","initialCanonicalUrl":"/","initialTree":["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],"initialHead":["$L3",null],"globalErrorComponent":"$4","notFound":["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$L5","$undefined",[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]]]}]}],"asNotFound":false,"children":[["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L6",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","loading":"$undefined","loadingStyles":"$undefined","hasLoading":false,"template":["$","$L7",null,{}],"templateStyles":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined","childProp":{"current":[["$","$L8",null,{"params":{},"searchParams":{}}],null],"segment":"__PAGE__"},"styles":[]}]}]}],null]}]]n"])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "5:[[["$","meta",null,{"charSet":"utf-8"}],null,null,null,null,null,null,null,null,null,null,["$","meta",null,{"name":"viewport","content":"width=device-width, initial-scale=1"}],null,null,null,null,null,null,null,null,null,null,[]],[null,null,null,null],null,null,[null,null,null,null,null],null,null,null,null,null]n3:[[["$","meta",null,{"charSet":"utf-8"}],["$","title",null,{"children":"Create Next App"}],["$","meta",null,{"name":"description","content":"Generated by create next app"}],null,null,null,null,n"])&lt;/script&gt; &lt;script&gt;self.__next_f.push([1, "ull,null,null,null,["$","meta",null,{"name":"viewport","content":"width=device-width, initial-scale=1"}],null,null,null,null,null,null,null,null,null,null,[]],[null,null,null,null],null,null,[null,null,null,null,null],null,null,null,null,null]n"])&lt;/script&gt; &lt;/body&gt; &lt;/html&gt;</pre> <hr /> <p>我很困惑,因为客户端组件似乎已预渲染了 HTML,但“Hello World”显然存在于源代码中。我期望看到类似于 React 根 DOM 节点的东西 - 基本上是一个空的 div 等待注入一些 HTML。我在这里缺少什么?</p>
P粉044526217
P粉044526217

全部回复(1)
P粉268654873

从这里

服务器和客户端组件在静态渲染期间的渲染方式不同:

  • 客户端组件的 HTML 和 JSON 已预渲染并缓存在服务器上。然后将缓存的结果发送到客户端进行水合作用。
  • 服务器组件由 React 在服务器上呈现,其负载用于生成 HTML。相同的渲染负载还用于混合客户端上的组件,从而导致客户端不需要 JavaScript。

现在,通过服务器和客户端组件,React 可以在客户端服务器上进行渲染,这意味着您可以可以在组件级别选择渲染环境。

默认情况下,app 路由器使用服务器组件,允许您轻松地在服务器上渲染组件并减少发送到客户端的 JavaScript 量。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号