React 服務器組件的使用方法詳解
簡介
最近,React 服務器組件受到了廣泛的關注和熱捧。這是因為 React 服務器組件允許開發(fā)人員將與組件相關的任務外包給服務器。這樣,開發(fā)人員就無需分發(fā)捆綁的 JavaScript 和外部 API 查詢,以便將組件水化,同時也避免了會導致客戶端應用程序延遲增加的情況。 在本文中,我們將討論什么是 React 服務器組件,以及如何將它們集成到構(gòu)建應用程序中。
什么是服務器組件?
服務器組件是 React 18 中引入的新功能,也是 Next.js 13 中的默認功能。服務器組件本質(zhì)上是一種從服務器檢索數(shù)據(jù)并在服務器上渲染的組件類型。這些內(nèi)容隨后會以客戶端應用程序可以呈現(xiàn)的格式流式傳輸?shù)娇蛻舳藨贸绦蛑小?br />服務器組件以自定義格式呈現(xiàn),這種格式?jīng)]有標準協(xié)議,但類似于 JSON 格式。反應 DOM 可識別這種格式,并在識別后對其進行適當?shù)某尸F(xiàn)。
引入 React 服務器組件概念的問題陳述
我們將創(chuàng)建一個場景來介紹服務器組件的概念??梢詫a(chǎn)品頁面結(jié)構(gòu)化如下:
const ProductPage = ({ productId })=> { return ( <> <ProductDetails productId={productId}> <ProductItem productId={productId} /> <MatchedItems productId={ productId } /> <ProductDetails> </> ) }
現(xiàn)在我們有很多方法去獲取組件中需要的數(shù)據(jù),如下所示,一次性獲取獲取到組件所需的數(shù)據(jù):
const ProductPage = ({ productId })=> { const data = fetchContentsFromAPI(); return ( <> <ProductDetails details={data.details} productId={productId}> <ProductItem item={data.product} productId={productId} /> <MatchedItems items={data.matchedItems} productId={productId} /> <ProductDetails> </> ) }
使用這種方法效果很好,而且有其優(yōu)點,例如:
- 這種方法適合用戶體驗,因為所有組件都是在獲取數(shù)據(jù)后在客戶端渲染的。
不過,它也可能帶來一些問題,例如:
- 由于它將數(shù)據(jù)內(nèi)容與父組件的子組件綁定在一起,因此會產(chǎn)生高度耦合。這會使這些組件難以維護。
- 這也違背了單一責任的理念,因為子組件并不單獨對其數(shù)據(jù)負責,因此依賴于父組件的數(shù)據(jù)。
- 加載時間長,因為它需要一次性獲取所有組件的所有數(shù)據(jù)。
為了實現(xiàn)單一責任,我們可以重組父組件,以如下方式顯示組件:
const ProductDetails = ({productId, children}) => { const details = fetchProductDetails(productId); return ( <> {{ children }} </> ) } const ProductItem = ({productId}) => { const item = fetchProductItem(productId); return (...) } const MatchedItems = ({productId}) => { const items = fetchMatchedItems(productId); return (...) } const ProductPage = ({ productId })=> { return ( <> <ProductDetails productId={productId}> <ProductItem productId={productId} /> <MatchedItems productId={productId} /> <ProductDetails> </> ) }
使用這種方法效果很好,而且有其優(yōu)點,例如:
- 單一責任: 每個組件對自己的數(shù)據(jù)負責。
但是,它可能會產(chǎn)生一些問題,例如:
- 它可能不適合用戶體驗,因為任何一個子組件都可能根據(jù)其 API 調(diào)用的加載時間,先于另一個組件在客戶端渲染,從而使用戶先于另一個組件看到頁面的一部分。
- 此外,由于
ProductDetails
組件將先于子組件(ProductItem、MatchedItems
)呈現(xiàn),因此數(shù)據(jù)的順序獲取會造成網(wǎng)絡瀑布流的情況。
這些方法各有利弊,但有一個共同的局限性。這個限制是,這兩種方法都需要從客戶端向服務器調(diào)用 API,這會造成客戶端和服務器之間的高延遲。
正是這一限制促使 React 團隊引入了服務器組件:服務器上的組件。由于服務器組件存在于服務器上,因此與在應用程序客戶端渲染的組件相比,它們可以更快地進行 API 調(diào)用并快速渲染。
雖然最初是為了解決高延遲的限制,但新的應用也隨之出現(xiàn)。由于組件駐留在服務器上,它們可以訪問服務器基礎設施,這意味著它們可以連接到數(shù)據(jù)庫并對其進行查詢。
React 服務器組件與客戶端組件的區(qū)別
服務器組件和客戶端組件的一個主要區(qū)別是,服務器組件在服務器上呈現(xiàn)組件,而客戶端組件在客戶端上呈現(xiàn)。
通常,對于客戶端的 React 應用程序來說,當用戶從服務器請求網(wǎng)頁時,服務器會將網(wǎng)頁(Javascript 文件)響應給瀏覽器。瀏覽器下載數(shù)據(jù)(Javascript 文件)并用于構(gòu)建網(wǎng)頁。 另一方面,客戶端組件會發(fā)送到客戶端,從而增加了應用程序的捆綁大?。蛻舳私M件是典型的傳統(tǒng) React 組件)。
另一個區(qū)別在于它們的呈現(xiàn)環(huán)境,這賦予了它們不同的屬性,具體解釋如下:
- 服務器組件不能使用 React 鉤子,如 useState、useReducer、useEffect 等。這是因為服務器組件是在服務器上呈現(xiàn)的,因此無法訪問可影響 DOM(文檔對象模型)的鉤子,而 DOM 僅存在于客戶端。另一方面,客戶端組件是普通的 React 組件,仍然可以訪問鉤子。
- 服務器組件無法訪問瀏覽器 API,如 SessionStorage、localStorage 等。另一方面,客戶端組件是普通的 React 組件,仍然可以訪問瀏覽器 API。
- 服務器組件可以對數(shù)據(jù)庫、內(nèi)部服務、文件系統(tǒng)等服務器專用數(shù)據(jù)源使用 async/await,而客戶端組件則不能直接訪問服務器專用數(shù)據(jù)源。
React 服務器組件與 React 服務器端呈現(xiàn)(SSR)的區(qū)別。
React 中的服務器端呈現(xiàn)(SSR)是指應用程序?qū)⒎掌魃系?React 組件轉(zhuǎn)化為完全呈現(xiàn)給客戶端的靜態(tài) HTML 頁面的能力。 另一方面,React 服務器組件(React Server Components)通過一個中介結(jié)構(gòu)(類似于 JSON 格式的協(xié)議)與 SSR 協(xié)作,從而在不向客戶端交付任何捆綁包的情況下實現(xiàn)渲染。
服務器組件案例研究。
我們將說明如何在傳統(tǒng)的 React 應用程序和 Next.js 應用程序中使用服務器組件。
在 React 應用程序中使用服務器組件。 在典型的 React 應用程序中,服務器組件就像普通的 React 組件一樣。
請注意,要在帶有 .tsx 文件的 typescript 組件中使用 async/await,需要將 typescript 版本升級到 5.1.1。要了解更多信息,請訪問此處
下面是一個服務器組件的示例:
// Server Component const BlogPost = async({id, isEditing}) => { const post = await db.posts.get(id); return ( <div> <h1>{post.title}</h1> <section>{post.body}</section> </div> ); }
客戶端組件看起來就像普通的 React 組件,但在組件文件中添加了 use client
指令。從技術上講,use client
指令聲明了服務器組件和客戶端組件之間的邊界。
// A client component 'use client' import React, { useState } from "react"; import { v4 as uuidv4 } from 'uuid'; const PostEditor = ({ blogPost }) => { const [post, setPost] = useState<any>({ id: uuidv4(), title: blogPost.title, content: blogPost.content, }) const onChange = (type: any, value: any)=> { switch(type){ case "title": setPost({...post, title: value}) break; case "content": setPost({...post, content: value}) break; default: break } } const submitPost = ()=> { // save blog post }; return ( <div> <div className="md:mx-auto px-6 md:px-0 mt-10 md:w-9/12"> <h1 className="my-4 text-center">Create Post</h1> <form onSubmit={submitPost}> <div className="mt-8"> <label className="text-white mb-2"> Title </label> <input type="text" placeholder="" value={post.title} required onChange={(e)=> onChange("title", e.target.value)} /> </div> <div className="mt-8"> <label className="text-white mb-2"> Add your Blog content </label> <textarea value={post.content} required onChange={(e)=> onChange("content", e.target.value)} ></textarea> </div> <div className="flex justify-end mt-8"> <button type="submit" className="px-4 py-4 bg-[#0e9f64] c-white border-radius" > Create Post </button> </div> </form> </div> </div> ); }; export default PostEditor;
在使用服務器和客戶端組件時,有一些特定的規(guī)則需要了解:
服務器組件不能導入到客戶端組件中,但客戶端組件可以導入到服務器組件中。我們將用下面的例子來說明如何將客戶端組件導入到服務器組件中:
// Server Component import db from 'db'; import NoteEditor from 'NoteEditor'; async function BlogPost({id, isEditing}) { const post = await db.posts.get(id); return ( <div> <h1>{post.title}</h1> <section>{post.body}</section> {isEditing ? <PostEditor blogPost={post} /> : null } </div> ); }
在上面的代碼中,我們將 PostEditor
(客戶端組件)導入了服務器組件。
當客戶端組件位于服務器組件內(nèi)時,服務器組件可以作為子 prop 傳遞給客戶端組件。
const ServerComponent1 = () => { return ( <ClientComponent> <ServerComponent2 /> </ClientComponent> ) }
在 Next 應用程序中使用服務器組件
默認情況下,服務器組件是在 Next 13 中新引入的 App 目錄中創(chuàng)建的普通 React 組件。
// Server Component const BlogPost = async({id, isEditing}) => { const post = await db.posts.get(id); return ( <div> <h1>{post.title}</h1> <section>{post.body}</section> </div> ); }
Next 13
中的客戶端組件看起來像普通的 React 組件,但在組件文件中添加了 use client
指令。
// A client component 'use client' import React, { useState } from "react"; import { v4 as uuidv4 } from 'uuid'; const PostEditor = ({ blogPost }) => { const [post, setPost] = useState<any>({ id: uuidv4(), title: blogPost.title, content: blogPost.content, }) const onChange = (type: any, value: any)=> { switch(type){ case "title": setPost({...post, title: value}) break; case "content": setPost({...post, content: value}) break; default: break } } const submitPost = ()=> { // save blog post }; return ( <div> <div className="md:mx-auto px-6 md:px-0 mt-10 md:w-9/12"> <h1 className="my-4 text-center">Create Post</h1> <form onSubmit={submitPost}> <div className="mt-8"> <label className="text-white mb-2"> Title </label> <input type="text" placeholder="" value={post.title} required onChange={(e)=> onChange("title", e.target.value)} /> </div> <div className="mt-8"> <label className="text-white mb-2"> Add your Blog content </label> <textarea value={post.content} required onChange={(e)=> onChange("content", e.target.value)} ></textarea> </div> <div className="flex justify-end mt-8"> <button type="submit" className="px-4 py-4 bg-[#0e9f64] c-white border-radius" > Create Post </button> </div> </form> </div> </div> ); }; export default PostEditor;
React 服務器組件的利與弊
我們將介紹在開發(fā)中使用服務器組件的優(yōu)點以及缺點。
優(yōu)點:
- 減少捆綁: 服務器組件是 "零捆綁 "組件,因為它們不會增加客戶端渲染的 Javascript 捆綁大小。
- 訪問服務器基礎設施: 使用服務器組件,可以無縫連接數(shù)據(jù)庫、文件系統(tǒng)等服務器基礎設施。
- 由于可以將 API 調(diào)用委托給在服務器上運行的服務器組件,因此減少了客戶端的延遲。
缺點:
- 服務器組件無法訪問客戶端功能。
- 由于服務器組件可提供與普通 SSR(服務器端渲染)應用程序幾乎相同的優(yōu)勢,而且許多人已習慣使用 SSR,因此其采用可能不會很快。
- 由于服務器組件可以訪問服務器基礎架構(gòu),它可能會導致應用程序設計不佳,因為它可能會鼓勵開發(fā)人員回避創(chuàng)建 API 或甚至獨立的后端,而是直接通過服務器組件執(zhí)行查詢和連接數(shù)據(jù)庫。
結(jié)論
在本文中,我們介紹了 React 中的服務器組件,并討論了它們的用途和優(yōu)點。React 服務器組件使我們能夠以一種全新的方式在 React 應用程序中將客戶端和服務器端渲染組件的優(yōu)點結(jié)合起來。
以上就是React 服務器組件的使用方法詳解的詳細內(nèi)容,更多關于React服務器組件的資料請關注腳本之家其它相關文章!
相關文章
React創(chuàng)建虛擬DOM的兩種方式小結(jié)
本文主要介紹了兩種創(chuàng)建React虛擬DOM的方式,包括JS方式和jsx方式,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2025-01-01React實現(xiàn)Excel文件的導出與在線預覽功能
這篇文章主要為大家詳細介紹了如何利用?React?18?的強大功能,演示如何使用?React?18?編寫?Excel?文件的導出與在線預覽功能,需要的小伙伴可以參考下2023-12-12解決React報錯No duplicate props allowed
這篇文章主要為大家介紹了React報錯No duplicate props allowed解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12React?Router掌握路由搭建與權限管控的操作方法(?從入門到精通)
本文詳細介紹了React?Router庫在React應用開發(fā)中的應用,包括其核心功能、安裝使用、基礎使用、核心組件和功能、路由參數(shù)和嵌套路由、編程式導航以及路由權限管理等方面,感興趣的朋友一起看看吧2025-01-01React?hook實現(xiàn)簡單的websocket封裝方式
這篇文章主要介紹了React?hook實現(xiàn)簡單的websocket封裝方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09react中使用echarts,并實現(xiàn)tooltip循環(huán)輪播方式
這篇文章主要介紹了react中使用echarts,并實現(xiàn)tooltip循環(huán)輪播方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01