用新的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 http://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.