在 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 的两个对象并将一个道具传递给列表,这将在单击时从列表中删除选定的列表项页面中的列表。

接下来是我们的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