在 React Native 應用程序中使用 Mobx 作為狀態管理器
已發表: 2022-03-10狀態管理是開發 JavaScript 應用程序的一個組成部分,尤其是 React 和 React Native 應用程序。 在本教程中,我們將學習如何使用 MobX 庫進行狀態管理; 了解核心概念、一些用例並構建一個簡單的示例。
注意: JavaScript 和 React Native 的基本知識將對您學習本教程大有裨益。
在 React 應用程序中使用 MobX
狀態是您的組件正在使用的數據——它保存組件所需的數據,並指示組件呈現的內容。 狀態管理是管理狀態如何更新並從一個組件傳遞到另一個組件的過程。 在應用程序中監控和處理數據可能很困難,這就是狀態管理庫的需要。 處理應用程序的所有數據可能有點令人生畏,尤其是當應用程序的規模和復雜性增長時,構建自己的狀態管理工具不僅耗時而且困難,這就是您可能想要使用狀態管理庫的原因。
但是,重要的是要知道狀態不是組件呈現的唯一數據,組件還可以呈現傳遞給它的道具。
狀態管理選項
React Native 應用程序的狀態管理庫包括: React Context API、Redux、MobX 和 Unstated Next。
儘管這些狀態管理器各有優缺點,但我個人推薦 MobX,因為它簡單,樣板代碼最少——它不需要你更改代碼,這是因為 MobX 的核心是並且看起來像 JavaScript; 你不需要改變架構來支持它(不像 Redux 和在較小程度上的 Context)。
事實上,這是一種隱形的抽象,在許多情況下,如果你去掉所有MobX代碼——@observable、 @computed 、 @action和觀察者裝飾器,你的代碼將完全一樣的工作(儘管它會有一些性能問題) 並且它不限於全局狀態。 這些是繼續將 MobX 作為 React Native 應用程序選擇的狀態管理器的一些原因。
儘管注意使用 MobX 作為狀態管理器的一些問題也很重要,其中一些包括它避免了有關如何實現它的規則,並且 MobX 可能難以調試,尤其是當您在不使用@actions
的情況下直接在組件中更改狀態時範圍。
什麼是 MobX?
根據官方文檔,MobX 是一個久經考驗的庫,它通過透明地應用函數式反應式編程使狀態管理變得簡單和可擴展。 MobX 將您的應用程序視為電子表格。 邏輯是任何可以從應用程序狀態派生的東西,都應該自動完成。

MobX 的核心原理和概念
MobX 與其他狀態管理器的區別在於以下概念。
1. 狀態
狀態是您的應用程序保存的數據——它大致是其內存的全部內容。 這也適用於您的組件。
2. 推導
在 MobX 中,任何可以從狀態派生而無需交互的東西都是派生。 推導的例子包括:
- 用戶界面,
- 後端附加組件,例如對服務器的更改。
MobX 有兩種主要的派生類型:
- 計算值
計算值主要是可以使用純函數從當前狀態派生的值。 - 反應
派生中的反應是由於應用程序狀態更改而發生的副作用。 它們類似於計算值,但不是產生新值,而是反應產生副作用,例如打印到控制台、發出網絡請求、增量更新 React 組件樹以修補 DOM 等等。
使用 MobX 時的一條黃金法則是,在基於當前狀態創建值時,使用計算值。
3. 行動
與派生不同,動作是導致應用程序狀態改變的代碼——改變狀態的代碼。 它們是改變狀態的任何東西。 使用 MobX,您可以在代碼中明確表示,Action 主要是用戶事件,例如輸入、後端數據推送甚至計劃事件。
為了更好地理解動作,讓我們看一下 MobX 文檔中的一個示例。
class Ticker { @observable tick = 0 @action increment() { this.tick++ // 'this' will always be correct } } const ticker = new Ticker() setInterval(ticker.increment, 1000)
在這裡,我們設置了一個初始值為 0 的@observable
刻度。接下來,我們創建了一個函數 increment,它也是一個動作,一旦每秒發出一個刻度,就會更新初始值。
MobX 中的 Observables
MobX 中的可觀察對像或可觀察值主要是 JavaScript 原語、普通對象、類、數組和映射。 它們主要通過首先聲明一個 observable 並向其添加一個值,然後通過添加一個 @observable 來調用它,如下所示:
observable(value) @observable classProperty = value
MobX 中的存儲架構方法
MobX 主要架構包括部分和想法,例如服務、存儲、視圖模型和容器——其中一些將在下面解釋。
- 服務
這通常是從容器調用的函數; 它們可用於從 API 獲取數據並添加到存儲中。 - 店鋪
顧名思義,這是應用程序使用的狀態的中心位置。 通常在 MobX 中,這些包括可觀察對象、變量、動作和計算屬性。 - 容器
這會調用service
並將數據從視圖模型放入視圖組件作為 React道具(應該用@observer
裝飾器標記)。
React 和本機應用程序中的 MobX
出於學習目的,在本教程中,我們將構建一個簡單的列表應用程序,允許用戶添加、查看和刪除列表項。 我們將在這個應用程序中使用 MobX 作為狀態管理器來添加列表、更新和從應用程序狀態中刪除它們。 但是,重要的是要注意您已經了解 JavaScript 和 React 的基本概念。
事不宜遲,讓我們開始吧!
設置您的環境
現在我們知道了 MobX 是什麼以及它是如何工作的,讓我來引導您完成項目的設置。
首先,讓我們使用以下內容創建一個項目,在您的終端上編寫以下代碼來初始化一個項目:
npx create-react-app listapp
上面的代碼將使用 create-react-app 包創建一個裸 React 應用程序。 進入項目目錄:
cd listapp
對於這個應用程序,我們將需要三個組件:
-
TitleInput
這將包含我們項目的標題和用於添加列表的輸入表單。 -
List
這將是一個允許用戶添加列表的輸入表單。 它將有一個添加按鈕來添加我們的列表項。 -
ListsDisplay
該組件將顯示所有用戶列表項以及用戶添加列表項時自動生成的刪除按鈕。
我們將使用 Store.js 來包含應用程序狀態和修改它的方法,類似於 Redux。 讓我們概述一下它們的用途。
-
mobx
這是我們將用於這個項目的狀態管理器。 -
mobx-react
這是 MobX 的官方 React 綁定。 -
bootstrap
我們將使用 bootstrap 4.5 版本來設計我們的項目。 -
uuid
這用於自動創建用於刪除列表的鍵。
完成之後,讓我們繼續安裝這些軟件包。 我將使用在 yarn 中完成的 npm 替代方案來安裝它們:
yarn add mobx mobx-react [email protected] uuid
安裝軟件包後,我們將通過在終端中運行以下代碼以開發模式啟動我們的應用程序:
yarn start
設置我們的應用商店
讓我們為我們的項目創建一個商店。 首先,在我們項目的根目錄中創建一個名為ListStore的文件,這將是我們應用程序狀態的中心位置。
對於這個應用程序,我們將需要創建一個ListStore ,以免我們在其他應用程序組件中使用它時重複我們自己。
/*** src/Store.js ***/ import { observable, action, computed } from "mobx"; import { v4 } from "uuid"; export class List { @observable value @observable done constructor (value) { this.id = v4() this.value = value } } export class ListStore { @observable lists = [] @observable filter = "" @action addList = (value) => { this.lists.push(new List(value)) } @action deleteList = (list) => { this.lists = this.lists.filter(t => t !== list) } @computed get filteredLists () { const matchCase = new RegExp(this.filter, "i") return this.lists.filter(list=> !this.filter || matchCase.test(list.value)) } }
在上面的代碼中,我們從mobx
導入了三個函數。
-
observable
這包含一個變量,可以在狀態發生變化時更新。 -
action
用於修改應用程序狀態。 -
computed
可以從現有狀態或其他計算值派生的值,在修改狀態後會發生變化。
List
類有兩個對象值,它們是done
和value
,它們將保存應用程序的初始狀態和更改時的修改。
我們希望我們的新列表自動創建一個鍵,以便我們可以在創建列表後自動獲得一個刪除按鈕,這裡 uuid 用於在我們的應用程序中自動創建鍵。
接下來,我們添加了一個addList
函數,該函數將在單擊時添加列表,方法是使用.push()
方法將列表推送到我們已經在@observable lists
數組中創建的數組中。
deleteList
函數接受List
作為屬性,它應該是用戶想要刪除的項目。 然後,在我們刪除選定的項目後,我們將this.Lists
的值設置為一個新數組。
addLists
和deleteList
都是操作,因為它們會在進行更改時修改我們的應用程序的狀態。

初始化 MobX 存儲
我們列表中的下一個是在我們的App.js中導入我們的商店並在我們的項目中使用它。
import React from 'react'; import Navbar from "./components/navbar"; import ListDisplay from "./components/ListDisplay"; import {ListStore} from './ListStore'; function App() { const store = new ListStore() return ( <div> <Navbar store={store}/> <ListDisplay store={store}/> </div> ); } export default App;
這裡我們導入了TitleInput和ListDisplay組件。 然後我們在App.js
中初始化了 store,以便能夠將其作為 props 傳遞給TitleInput和ListDisplay組件。
通常這會拋出一個錯誤,因為我們還沒有處理其他組件,所以讓我們這樣做。 讓我們構建ListDisplay
組件。
ListDisplay
該組件顯示我們添加的所有列表,並在添加新列表後自動生成刪除按鈕。
import React from 'react' import List from "./List"; import { observer } from 'mobx-react'; function ListDisplay(props) { const { deleteList, filteredLists } = props.store return ( <div> <div className="container"> {filteredLists.map(list => ( <List key={list.id} list={list} deleteList={deleteList} /> ))} </div> </div> ) } export default observer(ListDisplay)
對於這個組件,我們創建了一個函數ListDisplay
並使其成為觀察者,我們還從 store 中解構了list
和deletelist
函數,通過這樣做,我們更容易將其作為對象 props 傳遞。
接下來,我們映射filteredLists
列表以返回列表,然後我們通過將返回的項目作為道具傳遞給List組件來構建單個列表。
完成後,我們的組件應如下所示,並添加了列表:

接下來是添加一個List和TitleInput組件。
列表組件
就像我們的其他組件一樣,我們的List
組件將導出列表作為觀察者,以幫助商店觀察它的變化。
import React from 'react' import { observer } from 'mobx-react' function List(props) { return ( <div className="card"> <div className="card-body"> <div className="d-flex justify-content-between align-items-center"> <p className={`title ${props.list.done ? "text-secondary" : ""}`}> {props.list.value} </p> <div> <button onClick={props.deleteList.bind(this, props.list)} className="btn btn-danger font-weight-bold py-2 px-5 ml-2"> Delete </button> </div> </div> </div> </div> ) } export default observer(List)
我使用引導程序在第一組divs
中創建卡片,並將刪除圖標對齊到應用程序的右側。 首先,我們創建了一個卡片組件來處理我們的list
,然後我們為刪除button
創建了一個按鈕標籤,它將接受 this 的兩個對象並將一個 prop 傳遞給列表,這將在單擊時從列表中刪除選定的列表項頁面中的列表。

接下來是我們的TitleInput ,它將包含我們用於添加列表和項目標題的輸入表單。
TitleInput
與我們的其他項目類似,我們將添加一個@observer
函數,以便該組件能夠接受來自應用商店的道具。
import React, { useState } from 'react' import { observer } from 'mobx-react' function Navbar(props) { const [value, setValue] = useState("") const {addList} = props.store const prepareAddList = (e) => { e.preventDefault() addList(value) setValue("") } return ( <div className="container mt-3"> <h1 className="title">List App</h1> <form onSubmit={prepareAddList} className="form-group"> <div className="row ml-lg-2"> <input className="form-control-lg col-12 col-lg-9 col-sm-12 mr-3 border border-secondary" value={value} type="text" onChange={(e) => setValue(e.target.value)} placeholder="Enter list" /> <button className="col-lg-2 col-5 col-sm-5 mt-2 mt-lg-0 mt-sm-2 btn btn-lg btn-success font-weight-bold"> Add to List </button> </div> </form> </div> ) } export default observer(Navbar)
首先,我們初始化了一個初始狀態。 使用 React Hooks,我們添加了一個名為values
的初始狀態,我們將其設置為空字符串。 我們使用它來保存輸入字段中輸入的值。 要了解有關 React Hooks 的更多信息,您可以查看 David Abiodun 的這篇文章。
然後我們調用了一個對象,用於將列表添加到商店addList
並將其作為來自應用商店的 props 傳遞。
接下來,我們創建了一個函數preparedAddList
來接受輸入表單的事件對象,我們還添加了一個按鈕,用於在單擊時手動添加列表。
幾乎完成了,我們需要通過運行重新啟動我們的項目服務器:
yarn start
我們的TitleInput
應該是這樣的:

我們現在已經完成了所有應用程序組件,所以讓我們將它組裝到我們的App.js
中。 為此,我們需要導入組件titleInput
和ListDisplay
。 我們還需要從 Store 組件中導入我們的商店。
為了讓 MobX 在我們的 App 中工作,我們需要將 MobX 商店作為我們的 App 和各個組件中的道具傳遞,以便它們獲得商店中的屬性和功能。
import React from 'react'; import Navbar from "./components/navbar"; import ListDisplay from "./components/ListDisplay"; import {ListStore} from './ListStore'; function App() { const store = new ListStore() return ( <div> <Navbar store={store}/> <ListDisplay store={store}/> </div> ); } export default App;
完成後,我們的應用程序應如下所示:

結論
MobX 是一個很棒的狀態管理器,特別是對於基於 React 的應用程序,構建我們的列表應用程序,我們已經學習了 MobX、狀態、派生和動作的基本概念。 這個應用程序的工作版本可以在這裡找到:
您可以通過在您構建的下一個涉及狀態管理的應用程序中使用 MobX 來進一步實現這一點。 我很想看看你想出了什麼新東西。 您可以在下面的參考資料中閱讀有關 MobX 和狀態管理應用程序的更多信息。
資源和參考
- “React Native with MobX — 入門”,Nader Dabit,Medium
- 《概念與原則》MobX(官方文檔)
- “React Hooks 的最佳實踐”,Adeneye David Abiodun,Smashing Magazine