用新的Firebase v9.x Web SDK重構一個React應用
Firebase Web SDK第9版的發佈,在管理用户和查詢數據庫的方法上有了突破性的變化。在Firebase v8.x中編寫的代碼在v9.x中使用時將會出現錯誤,這就需要進行重構。
在這篇文章中,我們將學習如何重構一個使用Firebase Web SDK v8.x到v9.x的React應用程序,這也被稱為模塊化的Web SDK。對於我們的例子,我們將使用一個用v8.x構建的亞馬遜克隆,並將其重構到v9.x。
前提條件
要跟上這個教程,你應該熟悉React和Firebase v8.x,你還應該在你的機器上安裝Node.js。
介紹Firebase v9.x Web SDK
新的Web SDK擺脱了第8版中使用的命名空間方法。取而代之的是,它採用了一種優化的模塊化格式,以消除不使用的代碼,例如,樹形搖動,從而大大減少了JavaScript捆綁的大小。
向模塊化方法的過渡引入了一些破壞性的變化,使得新的庫向後不兼容,並導致v8.x中使用的代碼在新的Firebase v9.x SDK中出現錯誤。
下面的代碼顯示了新庫中引入的一些破壞性變化。
``` // VERSION 8 import firebase from 'firebase/app'; import 'firebase/auth';
firebase.initializeApp(); const auth = firebase.auth();
auth.onAuthStateChanged(user => { // Check for user status });
// VERSION 9 EQUIVALENT import { initializeApp } from 'firebase/app'; import { getAuth, onAuthStateChanged } from 'firebase/auth';
const firebaseApp = initializeApp(); const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => { // Check for user status });
```
上面的兩個代碼樣本都監控了一個用户狀態。雖然兩者使用的代碼行數相似,但在v9.x中,我們沒有導入firebase
命名空間或firebase/auth
副作用,該副作用將認證服務增強到firebase
命名空間中,而是導入並使用單個函數。
這些變化利用了現代JavaScript工具如Webpack和Rollup的代碼消除功能。
例如,上面的v8.x代碼包括以下代碼片斷。
``` auth.onAuthStateChanged(user => { // Check for user status });
```
auth
是一個命名空間和一個服務,包含onAuthStateChanged
方法。該命名空間還包含像signInWithEmailAndPassword
、createUserWithEmailAndPassword
、signOut
,這些方法沒有被代碼使用。當我們捆綁整個代碼時,這些未使用的方法也會被包含在捆綁中,從而導致相對大小的增加。
儘管像Webpack和Rollup這樣的捆綁器可以用來消除未使用的代碼,但由於命名空間的方法,它們將沒有任何效果。解決這個問題是重塑API表面的主要目標之一,以採取模塊化的形式。要了解更多關於新庫變化背後的原因,請查看Firebase官方博客。
Firebase兼容性庫
新的SDK還包括一個具有熟悉的API表面的兼容庫,它與v8.x完全兼容。兼容庫允許我們在同一個代碼庫中同時使用新舊API,使我們能夠逐步重構我們的應用而不破壞它。我們可以通過對導入路徑做一些調整來使用兼容庫,如下所示。
``` import firebase from 'firebase/compat/app'; import 'firebase/compat/auth'; import 'firebase/compat/firestore';
```
當我們重構我們的Amazon克隆應用時,我們將利用這個庫的優勢。
Firebase Web SDK v9.x的好處
簡而言之,Firebase Web SDK v9.x提供了縮小的尺寸和增加的整體性能。通過像Webpack和Rollup這樣的JavaScript工具來利用代碼消除功能,新的Web SDK提供了更快的網絡體驗。據Firebase官方Twitter賬户稱,由於採用了新的模塊化形狀,新的SDK據説比前代產品小了約80%。
設置我們的React應用進行重構
現在我們已經熟悉了新的SDK,讓我們來學習如何重構我們的v8.x應用。本節中我們將使用的亞馬遜克隆應用是一個使用Firebase和Strapi構建的電子商務應用。
在我們的應用中,我們使用Firebase來增加一些功能,比如用Firebase認證來管理用户身份,用Cloud Firestore來存儲認證用户購買的產品。我們使用Strapi來處理在應用程序上購買的產品的付款。最後,我們用Express.js創建了一個API,用Strapi客户端的祕密來響應即將用Firebase雲功能購買產品的客户。
你可以訪問該網站的部署版本,它看起來像下面的圖片。
請隨意玩玩這個應用,以便更好地理解我們在這篇文章中的工作內容。
設置亞馬遜的克隆應用
在我們開始編碼之前,首先,讓我們從GitHub上克隆repo並安裝必要的npm包。打開你的終端,導航到你想存儲React應用程序的文件夾。添加以下命令。
``` $ git clone https://github.com/Tammibriggs/Amazon-clone-FirebaseV8.git $ cd Amazon-clone-FirebaseV8
```
現在我們已經成功克隆了 repo,在安裝包之前,我們需要將package.json
文件中的Firebase版本改為v9.x。
在根目錄下,打開package.json
文件,用"firebase": "9.2.0"
替換依賴對象中的"firebase": "8.10.0"
。現在,讓我們通過在終端運行以下命令來安裝我們應用程序的依賴項。
``` $ npm install $ cd functions $ npm install
```
儘管我們已經設置並安裝了我們應用程序的所有依賴項,但如果我們嘗試用npm start
來運行應用程序,它就會出現錯誤。為了避免這種情況,我們需要修復我們的應用程序的破壞性變化,這一點我們很快就會做到。
React應用程序的結構
我們的應用程序的src
目錄的結構如下,但我們已經刪除了所有的樣式文件,使其看起來更短。
``` src ┣ Checkout ┃ ┣ Checkout.js ┃ ┣ CheckoutProduct.js ┃ ┗ Subtotal.js ┣ Header ┃ ┗ Header.js ┣ Home ┃ ┣ Home.js ┃ ┗ Product.js ┣ Login ┃ ┗ Login.js ┣ Orders ┃ ┣ Order.js ┃ ┗ Orders.js ┣ Payment ┃ ┣ axios.js ┃ ┗ Payment.js ┣ App.js ┣ firebase.js ┣ index.js ┣ reducer.js ┣ reportWebVitals.js ┗ StateProvider.js
```
我們將只處理使用Firebase服務的文件,firebase
、App.js
、Header.js
、Login.js
、Payment.js
和Orders.js
。
將亞馬遜的克隆文件重構為一個模塊化的方法
讓我們更新到v9.x的compat庫,幫助我們逐步遷移到模塊化方法,直到我們不再需要compat庫。
升級過程遵循一個重複的模式;首先,它將單一服務(如身份驗證)的代碼重構為模塊化風格,然後刪除該服務的compat庫。
更新導入到9.x版本的compat庫
前往src
目錄中的firebase.js
文件,修改v8.x的導入,使其看起來像以下代碼。
``` import firebase from 'firebase/app'; import 'firebase/auth'; import 'firebase/firestore';
```
僅僅做了一些改動,我們就將應用程序更新到了v9.x compat。現在,我們可以用npm start
來啟動我們的應用程序,它不會出現任何錯誤。我們還應該在本地啟動Firebase函數,以公開從Strapi獲取客户祕密的API。
在你的終端,改變到functions
目錄,運行以下命令來啟動該函數。
``` $ firebase emulators:start
```
重構認證代碼
在Login.js
,App.js
, 和Header.js
, 我們使用了Firebase認證服務。首先,讓我們重構Login.js
文件中的代碼,在這裏我們創建了創建用户的功能,並通過FirebasecreateUserWithEmailAndPassword
和signInWithEmailAndPassword
方法來簽署他們。當我們掃描Login.js
文件的時候,我們會看到下面的v8.x代碼。
``` // src/Login/Login.js const signIn = e => { ... // signIn an existing user with email and password auth .signInWithEmailAndPassword(email, password) .... }
const regiter = e => { ... // Create a new user with email and password using firebase auth .createUserWithEmailAndPassword(email, password) .... }
```
為了遵循模塊化的方法,我們將從auth
模塊中導入signInWithEmailAndPassword
和createUserWithEmailAndPassword
方法,然後更新代碼。重構後的版本將看起來像下面的代碼。
``` // src/Login/Login.js import {signInWithEmailAndPassword, createUserWithEmailAndPassword} from 'firebase/auth'
... const signIn = e => { ... // signIn an existing user with email and password signInWithEmailAndPassword(auth, email, password) ... } const regiter = e => { ... // Create a new user with email and password using firebase createUserWithEmailAndPassword(auth, email, password) ... }
```
現在,讓我們重構一下App.js
和Header.js
文件。在App.js
文件中,我們使用onAuthStateChanged
方法來監控用户登錄狀態的變化。
``` // src/App.js useEffect(() => { auth.onAuthStateChanged(authUser => { ... }) }, [])
```
上述代碼的模塊化v9.x看起來像下面這段。
``` // src/App.js import {onAuthStateChanged} from 'firebase/auth'
... useEffect(() => { onAuthStateChanged(auth, authUser => { ... }) }, [])
```
在Header.js
文件中,我們使用signOut
方法來簽出已認證的用户。
``` // src/Header/Header.js const handleAuthentication = () => { ... auth.signOut() ... }
```
更新上面的代碼,使其看起來像下面的代碼段。
``` // src/Header/Header.js import {signOut} from 'firebase/auth' ... const handleAuthentication = () => { ... signOut(auth) ... }
```
現在我們已經完成了對所有認證代碼的重構,現在是時候刪除compat庫以獲得我們的規模優勢了。在firebase.js
文件中,用以下代碼替換import 'firebase/compat/auth'
和const auth = firebaseApp.auth()
。
``` import {getAuth} from 'firebase/auth' ... const auth = getAuth(firebaseApp)
```
重構Cloud Firestore代碼
重構Cloud Firestore代碼的過程與我們剛才對認證代碼所做的相似。我們將與Payment.js
和Orders.js
文件一起工作。在Payment.js
,我們使用Firestore來存儲在網站上支付產品的用户的數據。在Payment.js
,我們會發現下面的v8.x代碼。
``` // src/Payment/Payment.js ... db .collection('users') .doc(user?.uid) .collection('orders') .doc(paymentIntent.id) .set({ basket: basket, amount: paymentIntent.amount, created: paymentIntent.created }) ...
```
為了重構代碼,我們首先要導入必要的函數,然後更新代碼的其他部分。上面代碼的v9.x看起來像下面這樣。
``` // src/Payment/Payment.js import {doc, setDoc} from 'firebase/firestore'
... const ref = doc(db, 'users', user?.uid, 'orders', paymentIntent.id) setDoc(ref, { basket: basket, amount: paymentIntent.amount, created: paymentIntent.created }) ...
```
在Orders.js
文件中,我們使用onSnapshot
方法來獲得Firestore中的數據的實時更新。v9.x的代碼看起來如下。
``` // src/Orders/Orders.js .... db .collection('users') .doc(user?.uid) .collection('orders') .orderBy('created', 'desc') .onSnapshot(snapshot => { setOrders(snapshot.docs.map(doc => ({ id: doc.id, data: doc.data() }))) }) ...
```
v9.x的對應代碼如下。
``` import {query, collection, onSnapshot, orderBy} from 'firebase/firestore'
... const orderedOrders = query(ref, orderBy('created', 'desc')) onSnapshot(orderedOrders, snapshot => { setOrders(snapshot.docs.map(doc => ({ id: doc.id, data: doc.data() }))) }) ...
```
現在我們已經完成了對所有Cloud Firestore代碼的重構,讓我們刪除compat庫。在firebase.js
文件中,用以下代碼替換import 'firebase/compat/firestore'
和const db = firebaseApp.firestore()
。
``` import { getFirestore } from "firebase/firestore"; ... const db = getFirestore(firebaseApp) ...
```
更新初始化代碼
將我們的亞馬遜克隆應用升級到新的模塊化v9.x語法的最後一步是更新初始化代碼。在firebase.js
文件中,用以下函數替換import firebase from 'firebase/compat/app';
和 constfirebaseApp = firebase.initializeApp(firebaseConfig)
。
``` import { initializeApp } from "firebase/app" ... const firebaseApp = initializeApp(firebaseConfig) ...
```
現在,我們已經成功地升級了我們的應用程序,以遵循新的v9.x模塊化格式。
結論
新的Firebase v9.x SDK由於採用了模塊化格式,所以比它的前輩v8.x提供了更快的網絡體驗。本教程介紹了新的SDK,並解釋瞭如何使用其緊湊的庫來反映一個React應用。你應該能夠按照本文介紹的方法和步驟,將你自己的應用程序升級到最新版本。
如果你在重構React應用程序時仍有困難,請務必查看以下Firebase支持社區。
The postRefactor a React app with the new Firebase v9.x Web SDKappeared first onLogRocket Blog.
- 在C 中把字符串轉換為整數的兩種簡單方法
- 如何在Flutter中實現任何UI
- Gatsby v4的新內容
- 創建一個Puppeteer微服務以部署到Google Cloud Functions
- 在Blazor中測試。一個完整的教程
- 在React中使用Plotly來構建動態圖表
- 分頁、加載更多按鈕和無限滾動的指南
- 用新的Firebase v9.x Web SDK重構一個React應用
- 在使用地理定位API時,你需要知道什麼?
- 在PostgreSQL v14中,JSON有什麼新功能?
- 使用React的函數式編程的基礎知識
- 使用Dart FFI訪問Flutter中的本地庫
- 使用視頻播放器插件在Flutter中處理視頻
- 改進過度約束的Rust庫API
- 用Svelte建立一個PWA
- 用Flask和D3.js構建交互式圖表
- 在Go中使用JSON。帶例子的指南
- 一篇文章入門Unix中的AWK命令!
- C 哈希
- Dotfiles - 什麼是Dotfile以及如何在Mac和Linux中創建它