用新的Firebase v9.x Web SDK重構一個React應用

語言: CN / TW / HK

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 方法。該命名空間還包含像signInWithEmailAndPasswordcreateUserWithEmailAndPasswordsignOut ,這些方法沒有被代碼使用。當我們捆綁整個代碼時,這些未使用的方法也會被包含在捆綁中,從而導致相對大小的增加。

儘管像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%。

Firebase Tweet v9 80 Percent Size

設置我們的React應用進行重構

現在我們已經熟悉了新的SDK,讓我們來學習如何重構我們的v8.x應用。本節中我們將使用的亞馬遜克隆應用是一個使用Firebase和Strapi構建的電子商務應用。

在我們的應用中,我們使用Firebase來增加一些功能,比如用Firebase認證來管理用户身份,用Cloud Firestore來存儲認證用户購買的產品。我們使用Strapi來處理在應用程序上購買的產品的付款。最後,我們用Express.js創建了一個API,用Strapi客户端的祕密來響應即將用Firebase雲功能購買產品的客户。

你可以訪問該網站的部署版本,它看起來像下面的圖片。

Amazon Clone App

請隨意玩玩這個應用,以便更好地理解我們在這篇文章中的工作內容。

設置亞馬遜的克隆應用

在我們開始編碼之前,首先,讓我們從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服務的文件,firebaseApp.jsHeader.jsLogin.jsPayment.jsOrders.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 文件中的代碼,在這裏我們創建了創建用户的功能,並通過FirebasecreateUserWithEmailAndPasswordsignInWithEmailAndPassword 方法來簽署他們。當我們掃描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 模塊中導入signInWithEmailAndPasswordcreateUserWithEmailAndPassword 方法,然後更新代碼。重構後的版本將看起來像下面的代碼。

``` // 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.jsHeader.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.jsOrders.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.