Next.js 13에서 "클라이언트 사용" 지시문이 작동하는 방식
P粉044526217
2023-08-26 21:55:31
<p>Next.js 13.4와 새로운 <code>app/</code> 디렉토리를 사용하여 서버 측 렌더링에 대해 배우려고 합니다. 내가 이해한 바로는 모든 구성 요소는 기본적으로 <em>서버</em> 구성 요소입니다(즉, 서버 측에서 렌더링됨). </p>
<p>그러나 <code>'use client'</code> 지시문을 사용하여 구성 요소를 <em>client</em> 구성 요소로 만들 수 있습니다. </p>
<p> 아래에서는 간단한 "Hello World" 구성 요소를 먼저 서버 구성 요소로 설정한 다음 클라이언트 구성 요소로 설정했습니다. 각각의 경우에 페이지 소스 코드를 비교합니다.</p>
<h3><code>src/app/page.js</code>(服务器组件)</h3>
<pre class="brush:php;toolbar:false;">기본 함수 내보내기 Home() {
반품 (
<메인>
<h1>Hello World</h1>
</메인>
)
}</pre>
<p>크롬 > 查看页면源代码</p>
<pre class="brush:php;toolbar:false;"><!DOCTYPE html>
<html lang="ko">
<머리>
<meta charSet="utf-8" />
<title>다음 앱 만들기</title>
<meta name="description" content="다음 앱 생성으로 생성됨" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<script src="/_next/static/chunks/polyfills.js" noModule=""></script>
</머리>
<본문>
<메인>
<h1>Hello World</h1>
</메인>
<script src="/_next/static/chunks/webpack.js" async=""></script>
<script src="/_next/static/chunks/main-app.js" async=""></script>
<script>(self.__next_f = self.__next_f || []).push([0])</script>
<script>self.__next_f.push([1, "0:"$L1"n"])</script>
<script>self.__next_f.push([1, "2:I{"id":"(app-client)/./node_modules/next/dist/client/comComponents/app-router.js","chunks ":["webpack:static/chunks/webpack.js"],"name":"","async":false}n4:I{"id":"(app-client)/./node_modules/next/ dist/client/comComponents/error-boundary.js","chunks":["webpack:static/chunks/webpack.js"],"name":"","async":false}n6:I{"id ":"(app-client)/./node_modules/next/dist/client/comComponents/layout-router.js","chunks":["app-client-internals:static/chunks/app-client-internals.js" js"],"name":"","async":false}n7:I{"id":"(app-client)/"])</script>
<스크립트>self.__next_f.push([1, "./node_modules/next/dist/client/comComponents/render-from-template-context.js","chunks":["app-client-internals:static /chunks/app-client-internals.js"],"name":"","async":false}n"])</script>
<script>self.__next_f.push([1, "1:[[],["$","$L2",null,{"assetPrefix":"","initialCanonicalUrl":"/","initialTree ":["",{"children":["__PAGE__",{}]},"$undefine","$undefine",true],"initialHead":["$L3",null],"globalErrorComponent" :"$4","notFound":["$","html",null,{"lang":"en","children":["$","body",null,{"children":[ "$L5","$undefine",[["$","title",null,{"children":"404: 이 페이지를 찾을 수 없습니다."}],["$","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;배경:#fff;margin :0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media(prefers-color-scheme:dark){body{color:#fff;배경:# 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":"이 페이지를 찾을 수 없습니다."}]}]]}]}]]]}]}],"asNotFound":false,"children":[["$","html",null,{"lang":"en","children":["$","body",null,{" children":["$","$L6",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefine","errorStyles":"$undefine ","loading":"$undefine","loadingStyles":"$undefine","hasLoading":false,"template":["$","$L7",null,{}],"templateStyles": "$undefine","notFound":"$undefine","notFoundStyles":"$undefine","childProp":{"current":[["$","main",null,{"children":[ "$","h1",null,{"children":"Hello World"}]}],null],"segment":"__PAGE__"},"styles":[]}]}]}],null ]}]]n"])</script>
<스크립트>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":"다음 앱 만들기"}],["$","meta",null,{"name":"description","content":"다음 앱 만들기에 의해 생성됨"}],null, null,null,null,n"])</script>
<script>self.__next_f.push([1, "ull,null,null,null,["$","meta",null,{"name":"viewport","content":"width=device -width, 초기 크기=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"])</script>
</body>
</html></pre>
<h3><code>src/app/page.js</code>(客户端组件)</h3>
<pre class="brush:php;toolbar:false;">'클라이언트 사용';
기본 함수 내보내기 Home() {
반품 (
<메인>
<h1>Hello World</h1>
</메인>
)
}</pre>
<p>Chrome > 查看页面源代码</p>
<pre class="brush:php;toolbar:false;"><!DOCTYPE html>
<html lang="en">
<head>
<meta charSet="utf-8" />
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="/_next/static/chunks/polyfills.js" noModule=""></script>
</head>
<body>
<main>
<h1>Hello World</h1>
</main>
<script src="/_next/static/chunks/webpack.js" async=""></script>
<script src="/_next/static/chunks/main-app.js" async=""></script>
<script>(self.__next_f = self.__next_f || []).push([0])</script>
<script>self.__next_f.push([1, "0:"$L1"n"])</script>
<script>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)/"])</script>
<script>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"])</script>
<script>self.__next_f.push([1, "1:[[],["$","$L2",null,{"assetPrefix":"","initialCanonicalUrl":"/","initialTree ":["",{"children":["__PAGE__",{}]},"$undefine","$undefine",true],"initialHead":["$L3",null],"globalErrorComponent" :"$4","notFound":["$","html",null,{"lang":"en","children":["$","body",null,{"children":[ "$L5","$undefine",[["$","title",null,{"children":"404: 이 페이지를 찾을 수 없습니다."}],["$","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;배경:#fff;margin :0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media(prefers-color-scheme:dark){body{color:#fff;배경:# 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":"이 페이지를 찾을 수 없습니다."}]}]]}]}]]]}]}],"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"])</script>
<스크립트>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":"다음 앱 만들기"}],["$","meta",null,{"name":"description","content":"다음 앱 만들기에 의해 생성됨"}],null, null,null,null,n"])</script>
<script>self.__next_f.push([1, "ull,null,null,null,["$","meta",null,{"name":"viewport","content":"width=device -width, 초기 크기=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"])</script>
</body>
</html></pre>
<시간 />
<p>我很困惑,因为客户端组件似乎已预渲染了 HTML,但“Hello World”显然存于源代码中。我期望看到类似于 React 根 DOM节点的东西 - 基本上是一个공적 div 等待注入一些 HTML。내가 어디에 있나요?</p>
여기부터
서버 및 클라이언트 구성 요소는 정적 렌더링 중에 다르게 렌더링됩니다.
이제 서버 및 클라이언트 구성 요소를 사용하면 React는 클라이언트와 서버 모두에서 렌더링할 수 있습니다. 즉, 구성 요소 수준에서 렌더링 환경을 선택할 수 있습니다.
기본적으로
app
라우터는 서버 구성 요소를 사용하므로 서버에서 구성 요소를 쉽게 렌더링하고 클라이언트에 전송되는 JavaScript의 양을 줄일 수 있습니다.