React 服務(wù)器組件的使用方法詳解
簡介
最近,React 服務(wù)器組件受到了廣泛的關(guān)注和熱捧。這是因?yàn)?React 服務(wù)器組件允許開發(fā)人員將與組件相關(guān)的任務(wù)外包給服務(wù)器。這樣,開發(fā)人員就無需分發(fā)捆綁的 JavaScript 和外部 API 查詢,以便將組件水化,同時(shí)也避免了會(huì)導(dǎo)致客戶端應(yīng)用程序延遲增加的情況。 在本文中,我們將討論什么是 React 服務(wù)器組件,以及如何將它們集成到構(gòu)建應(yīng)用程序中。
什么是服務(wù)器組件?
服務(wù)器組件是 React 18 中引入的新功能,也是 Next.js 13 中的默認(rèn)功能。服務(wù)器組件本質(zhì)上是一種從服務(wù)器檢索數(shù)據(jù)并在服務(wù)器上渲染的組件類型。這些內(nèi)容隨后會(huì)以客戶端應(yīng)用程序可以呈現(xiàn)的格式流式傳輸?shù)娇蛻舳藨?yīng)用程序中。
服務(wù)器組件以自定義格式呈現(xiàn),這種格式?jīng)]有標(biāo)準(zhǔn)協(xié)議,但類似于 JSON 格式。反應(yīng) DOM 可識別這種格式,并在識別后對其進(jìn)行適當(dāng)?shù)某尸F(xiàn)。
引入 React 服務(wù)器組件概念的問題陳述
我們將創(chuàng)建一個(gè)場景來介紹服務(wù)器組件的概念??梢詫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)點(diǎn),例如:
- 這種方法適合用戶體驗(yàn),因?yàn)樗薪M件都是在獲取數(shù)據(jù)后在客戶端渲染的。
不過,它也可能帶來一些問題,例如:
- 由于它將數(shù)據(jù)內(nèi)容與父組件的子組件綁定在一起,因此會(huì)產(chǎn)生高度耦合。這會(huì)使這些組件難以維護(hù)。
- 這也違背了單一責(zé)任的理念,因?yàn)樽咏M件并不單獨(dú)對其數(shù)據(jù)負(fù)責(zé),因此依賴于父組件的數(shù)據(jù)。
- 加載時(shí)間長,因?yàn)樗枰淮涡垣@取所有組件的所有數(shù)據(jù)。
為了實(shí)現(xiàn)單一責(zé)任,我們可以重組父組件,以如下方式顯示組件:
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)點(diǎn),例如:
- 單一責(zé)任: 每個(gè)組件對自己的數(shù)據(jù)負(fù)責(zé)。
但是,它可能會(huì)產(chǎn)生一些問題,例如:
- 它可能不適合用戶體驗(yàn),因?yàn)槿魏我粋€(gè)子組件都可能根據(jù)其 API 調(diào)用的加載時(shí)間,先于另一個(gè)組件在客戶端渲染,從而使用戶先于另一個(gè)組件看到頁面的一部分。
- 此外,由于
ProductDetails
組件將先于子組件(ProductItem、MatchedItems
)呈現(xiàn),因此數(shù)據(jù)的順序獲取會(huì)造成網(wǎng)絡(luò)瀑布流的情況。
這些方法各有利弊,但有一個(gè)共同的局限性。這個(gè)限制是,這兩種方法都需要從客戶端向服務(wù)器調(diào)用 API,這會(huì)造成客戶端和服務(wù)器之間的高延遲。
正是這一限制促使 React 團(tuán)隊(duì)引入了服務(wù)器組件:服務(wù)器上的組件。由于服務(wù)器組件存在于服務(wù)器上,因此與在應(yīng)用程序客戶端渲染的組件相比,它們可以更快地進(jìn)行 API 調(diào)用并快速渲染。
雖然最初是為了解決高延遲的限制,但新的應(yīng)用也隨之出現(xiàn)。由于組件駐留在服務(wù)器上,它們可以訪問服務(wù)器基礎(chǔ)設(shè)施,這意味著它們可以連接到數(shù)據(jù)庫并對其進(jìn)行查詢。
React 服務(wù)器組件與客戶端組件的區(qū)別
服務(wù)器組件和客戶端組件的一個(gè)主要區(qū)別是,服務(wù)器組件在服務(wù)器上呈現(xiàn)組件,而客戶端組件在客戶端上呈現(xiàn)。
通常,對于客戶端的 React 應(yīng)用程序來說,當(dāng)用戶從服務(wù)器請求網(wǎng)頁時(shí),服務(wù)器會(huì)將網(wǎng)頁(Javascript 文件)響應(yīng)給瀏覽器。瀏覽器下載數(shù)據(jù)(Javascript 文件)并用于構(gòu)建網(wǎng)頁。 另一方面,客戶端組件會(huì)發(fā)送到客戶端,從而增加了應(yīng)用程序的捆綁大?。蛻舳私M件是典型的傳統(tǒng) React 組件)。
另一個(gè)區(qū)別在于它們的呈現(xiàn)環(huán)境,這賦予了它們不同的屬性,具體解釋如下:
- 服務(wù)器組件不能使用 React 鉤子,如 useState、useReducer、useEffect 等。這是因?yàn)榉?wù)器組件是在服務(wù)器上呈現(xiàn)的,因此無法訪問可影響 DOM(文檔對象模型)的鉤子,而 DOM 僅存在于客戶端。另一方面,客戶端組件是普通的 React 組件,仍然可以訪問鉤子。
- 服務(wù)器組件無法訪問瀏覽器 API,如 SessionStorage、localStorage 等。另一方面,客戶端組件是普通的 React 組件,仍然可以訪問瀏覽器 API。
- 服務(wù)器組件可以對數(shù)據(jù)庫、內(nèi)部服務(wù)、文件系統(tǒng)等服務(wù)器專用數(shù)據(jù)源使用 async/await,而客戶端組件則不能直接訪問服務(wù)器專用數(shù)據(jù)源。
React 服務(wù)器組件與 React 服務(wù)器端呈現(xiàn)(SSR)的區(qū)別。
React 中的服務(wù)器端呈現(xiàn)(SSR)是指應(yīng)用程序?qū)⒎?wù)器上的 React 組件轉(zhuǎn)化為完全呈現(xiàn)給客戶端的靜態(tài) HTML 頁面的能力。 另一方面,React 服務(wù)器組件(React Server Components)通過一個(gè)中介結(jié)構(gòu)(類似于 JSON 格式的協(xié)議)與 SSR 協(xié)作,從而在不向客戶端交付任何捆綁包的情況下實(shí)現(xiàn)渲染。
服務(wù)器組件案例研究。
我們將說明如何在傳統(tǒng)的 React 應(yīng)用程序和 Next.js 應(yīng)用程序中使用服務(wù)器組件。
在 React 應(yīng)用程序中使用服務(wù)器組件。 在典型的 React 應(yīng)用程序中,服務(wù)器組件就像普通的 React 組件一樣。
請注意,要在帶有 .tsx 文件的 typescript 組件中使用 async/await,需要將 typescript 版本升級到 5.1.1。要了解更多信息,請?jiān)L問此處
下面是一個(gè)服務(wù)器組件的示例:
// 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
指令。從技術(shù)上講,use client
指令聲明了服務(wù)器組件和客戶端組件之間的邊界。
// 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;
在使用服務(wù)器和客戶端組件時(shí),有一些特定的規(guī)則需要了解:
服務(wù)器組件不能導(dǎo)入到客戶端組件中,但客戶端組件可以導(dǎo)入到服務(wù)器組件中。我們將用下面的例子來說明如何將客戶端組件導(dǎo)入到服務(wù)器組件中:
// 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
(客戶端組件)導(dǎo)入了服務(wù)器組件。
當(dāng)客戶端組件位于服務(wù)器組件內(nèi)時(shí),服務(wù)器組件可以作為子 prop 傳遞給客戶端組件。
const ServerComponent1 = () => { return ( <ClientComponent> <ServerComponent2 /> </ClientComponent> ) }
在 Next 應(yīng)用程序中使用服務(wù)器組件
默認(rèn)情況下,服務(wù)器組件是在 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 服務(wù)器組件的利與弊
我們將介紹在開發(fā)中使用服務(wù)器組件的優(yōu)點(diǎn)以及缺點(diǎn)。
優(yōu)點(diǎn):
- 減少捆綁: 服務(wù)器組件是 "零捆綁 "組件,因?yàn)樗鼈儾粫?huì)增加客戶端渲染的 Javascript 捆綁大小。
- 訪問服務(wù)器基礎(chǔ)設(shè)施: 使用服務(wù)器組件,可以無縫連接數(shù)據(jù)庫、文件系統(tǒng)等服務(wù)器基礎(chǔ)設(shè)施。
- 由于可以將 API 調(diào)用委托給在服務(wù)器上運(yùn)行的服務(wù)器組件,因此減少了客戶端的延遲。
缺點(diǎn):
- 服務(wù)器組件無法訪問客戶端功能。
- 由于服務(wù)器組件可提供與普通 SSR(服務(wù)器端渲染)應(yīng)用程序幾乎相同的優(yōu)勢,而且許多人已習(xí)慣使用 SSR,因此其采用可能不會(huì)很快。
- 由于服務(wù)器組件可以訪問服務(wù)器基礎(chǔ)架構(gòu),它可能會(huì)導(dǎo)致應(yīng)用程序設(shè)計(jì)不佳,因?yàn)樗赡軙?huì)鼓勵(lì)開發(fā)人員回避創(chuàng)建 API 或甚至獨(dú)立的后端,而是直接通過服務(wù)器組件執(zhí)行查詢和連接數(shù)據(jù)庫。
結(jié)論
在本文中,我們介紹了 React 中的服務(wù)器組件,并討論了它們的用途和優(yōu)點(diǎn)。React 服務(wù)器組件使我們能夠以一種全新的方式在 React 應(yīng)用程序中將客戶端和服務(wù)器端渲染組件的優(yōu)點(diǎn)結(jié)合起來。
以上就是React 服務(wù)器組件的使用方法詳解的詳細(xì)內(nèi)容,更多關(guān)于React服務(wù)器組件的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React創(chuàng)建虛擬DOM的兩種方式小結(jié)
本文主要介紹了兩種創(chuàng)建React虛擬DOM的方式,包括JS方式和jsx方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01React實(shí)現(xiàn)動(dòng)態(tài)輪播圖的使用示例
輪播組件是常見的一種方式,用來展示圖像、信息或者是廣告,本文就來介紹一下React實(shí)現(xiàn)動(dòng)態(tài)輪播圖的使用示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12React實(shí)現(xiàn)Excel文件的導(dǎo)出與在線預(yù)覽功能
這篇文章主要為大家詳細(xì)介紹了如何利用?React?18?的強(qiáng)大功能,演示如何使用?React?18?編寫?Excel?文件的導(dǎo)出與在線預(yù)覽功能,需要的小伙伴可以參考下2023-12-12解決React報(bào)錯(cuò)No duplicate props allowed
這篇文章主要為大家介紹了React報(bào)錯(cuò)No duplicate props allowed解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12React?Router掌握路由搭建與權(quán)限管控的操作方法(?從入門到精通)
本文詳細(xì)介紹了React?Router庫在React應(yīng)用開發(fā)中的應(yīng)用,包括其核心功能、安裝使用、基礎(chǔ)使用、核心組件和功能、路由參數(shù)和嵌套路由、編程式導(dǎo)航以及路由權(quán)限管理等方面,感興趣的朋友一起看看吧2025-01-01React?hook實(shí)現(xiàn)簡單的websocket封裝方式
這篇文章主要介紹了React?hook實(shí)現(xiàn)簡單的websocket封裝方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09react中使用echarts,并實(shí)現(xiàn)tooltip循環(huán)輪播方式
這篇文章主要介紹了react中使用echarts,并實(shí)現(xiàn)tooltip循環(huán)輪播方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01React+Antd 實(shí)現(xiàn)可增刪改表格的示例
這篇文章主要介紹了React+Antd實(shí)現(xiàn)可增刪改表格的示例,幫助大家更好的理解和學(xué)習(xí)使用React,感興趣的朋友可以了解下2021-04-04