强大的状态管理工具-Mobx

2023-12-18 17:38

本文主要是介绍强大的状态管理工具-Mobx,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

Mobx是一款精准的状态管理工具库,如果你在 React 和 React Native 应用中使用过 Redux ,那毫不犹豫地说,MobX 的简单性将成为你状态管理的不二之选,本文主要讲的是关于Mobx在React-native下的使用和常见问题。

常见API

在使用Mobx之前,首先介绍几个常见的API

1. observable

Mobx如此简单的原因之一,就是使用了可观察数据(observable Data),简单来说,可观察数据就是可以观察到数据的读取,写入,并进行拦截
Mobx中提供了observable接口来定义可观察数据,可观察数据的类型可以使基本数据类型,object,array或者ES6中的Map类型,
注意:数组经过observable包装之后,就不是Array类型了,而是Mobx中的一个特殊类型,observable类型。
虽然数据类型不一样,但是使用方式和原来使用方式一致(原始数据类型除外)

const Array =  observable([1,2,3]);
const object =  observable({name: 'Jay'});
const Map =  observable(new Map([['name','ding']]));console.log(Array[0])  // 1
console.log(object.name)  // Jay
console.log(Map.get('name'))  // ding

@observable

装饰器可以再ES7或者TypeScript类属性中使用,将其转换成可观察的。 @observable可以再字段和属性getter上使用,对于对象的哪部分需要成为可观察对象,@observable 提供了细粒度的控制。

import { observable, computed } from "mobx";class Order {@observable price = 0;@observable amount = 1;@computed get total() {return this.price * this.amount;}
}

observer

observer接收一个React-native组件作为参数,并将其转换成响应式组件


@observer export default class App extends Component  {render() {return (<View></View>)}
}

响应式组件,即当且仅当组件依赖的可观察对象数据发生改变时,组件才会自动相应并且重新渲染,而在传统的react-native应用中,当状态属性变化后会先调用shouldComponentUpdate,该方法会深层对比前后状态和属性是否发生改变,再确定是否更新组件。

shouldComponentUpdate是很消耗性能的,Mobx通过可观察数据,精确地知道组件是否需要更新,减少了利用shouldComponentUpdate这个方法,这是Mobx性能好的原因之一
陷阱:Mobx可以做很多事,但是它还是无法将原始数据类型转换成可观察的,所以值是不可观察的,但是对象的属性可以被观察,这意味着 @observer 实际上是对间接引用(dereference)值的反应。

computed

计算值(computed values)是可以根据现有状态或其它计算值衍生出的值,计算的耗费是不可低估的,computed尽可能帮你减少其中的耗费,它们是高度优化的。
computed values是自动帮你从你的状态(state)值和其他计算辅助值来计算的。MobX做了很多的优化。当参与计算的值没有发生改变,Computed是不会重新运行。如果参与计算的值没有被使用,Computed values是暂停的。如果Computed values不再是观察者(observed),那么在UI上也会把它除掉,MobX能自动做垃圾回收,用法如下:

class foo {@observable length: 2,@computed get squared() {return this.length * this.length;}
}

Autorun

Autorun是用在一些你想要产生一个不用观察者参与的被动调用函数里面。当autorun被使用的时候,一旦依赖项发生变化,autorun提供的函数就会被执行。与之相反的是,computed提供的函数只会在他有自己的观察员(observers)的时候才会评估是否重新执行,否则它的值被认为是无用的
综上所述:如果你需要一个自动运行但确不会产生任何新的值的结果的函数,就可以使用Autorun,其他情况可以使用computed,Autorun只是作用于如果达到某个效果或者功能,而不是计算某些值
就像 @ observer 装饰器/函数,autorun 只会观察在执行提供的函数时所使用的数据。

var numbers = observable([1,2,3]);
var sum = computed(() => numbers.reduce((a, b) => a + b, 0));
var disposer = autorun(() => console.log(sum.get()));
// 输出 '6'
numbers.push(4);
// 输出 '10'disposer();
numbers.push(5);
// 不会再输出任何值。`sum` 不会再重新计算

action

  • 任何应用程序都有操作(action),action是任何改变状态的事物,使用Mobx
    ,可以通过标记他们在你的代码中显式的显示你的操作(action),它会更好的组织你的代码,它们用于修改可观察量或具有副作用的任何函数中。
    需要注意的是:action是用在strict mode 中的

    用法:

  • action(fn)
  • action(name, fn)
  • @action classMethod() {}
  • @action(name) classMethod () {}
  • @action boundClassMethod = (args) => { body }
  • @action(name) boundClassMethod = (args) => { body }
  • @action.bound classMethod() {}
  // 添加图片@action addImg = () => {ImagePicker.openPicker({multiple: true,waitAnimationEnd: false,includeExif: true,forceJpg: true,maxFiles: 9 - this.imgs.length,compressImageQuality: 0.5,}).then((images) => {console.log(images)}).catch((err) => {console.warn(err)})}

2.Action仅仅作用于当前运行的函数,而不是作用于当前函数调用的函数,这意味着在一些定时器或者网络请求,异步处理的情况下,它们的回调函数无法对状态改变,这些回调函数都应该包裹在action里面,但是,如果你使用了async / await的话,最好的方式应该是使用 runInAction 来让它变得更加简单

@action /*optional*/ updateDocument = async () => {const data = await fetchDataFromUrl();/* required in strict mode to be allowed to update state: */runInAction("update state after fetching data", () => {this.data.replace(data);this.isSaving = true;})
}

常见可观察类型

Observable 对象

observable.object方法将对象变为可观察的,它实际上是把对象的所有属性转换为可观察的,存放到一个代理对象上,以减少对原对象的污染,默认情况下,observable是递归应用的,所以如果对象的某个值是一个对象或数组,那么该值也将通过 observable 传递

import {observable, autorun, action} from "mobx"var person = observable({name : 'jack',age:24,sex:'男'
})

Observable 数组

与对象类似,可以使用Observable.array(array)或者将数组传给 observable,可以将数组转换成可观察的,这也是递归的,所以数组中的所有(未来的)值都会是可观察的。

import {observable, autorun} from "mobx";
var todos = observable([{ title: "Spoil tea", completed: true },{ title: "Make coffee", completed: false }
]);
autorun(() => {console.log("Remaining:", todos.filter(todo => !todo.completed).map(todo => todo.title).join(", "));
});
// 输出: 'Remaining: Make coffee'todos[0].completed = false;
// 输出: 'Remaining: Spoil tea, Make coffee'todos[2] = { title: 'Take a nap', completed: false };
// 输出: 'Remaining: Spoil tea, Make coffee, Take a nap'todos.shift();
// 输出: 'Remaining: Make coffee, Take a nap'

除了可以使用所有的内置函数,observable数组还提供了好多方法供我们使用

  • clear() -- 从数组中删除所有项
  • replace(newItems) -- 用新元素替换数组中所有已存在的元素
  • remove(value) -- 通过值从数组中移除一个单个的元素。

注意:

不同于sort和reverse函数的实现,observableArray.sort 和 observableArray.reverse 不会改变数组本身,而只是返回一个排序过/反转过的拷贝,在 MobX 5 及以上版本中会出现警告。推荐使用 array.slice().sort() 来替代。

Observable Map

与数组的处理方式类似,Mobx也实现了一个ObservableMap类,不过只支持字符串。数字或Bool值作为键,ObservableMap在可观察对象的基础上,还要使键的增删可观察。它可以看做两个可观察映射和一个可观察数组的组合:

import {observable, autorun} from "mobx"
const map = observable(new Map());autorun(() => {console.log(map.get('key'));
});map.set('key', 'value'); // 新增 key-value 键值对,输出 value
map.set('key', 'anotherValue'); // 修改为 key-anotherValue,输出 anotherValue
map.set('prop', 'value'); // 不输出
map.delete('prop'); // 不输出

优化React 组件

避免在父组件中访问子组件的属性

在文档中也有提到过这个问题,Mobx对于一个observer组件,是通过访问属性来访问以来的,所以哪怕父组件里没有用到这个属性,只是为了作为props传给子组件,Mobx还是会算它依赖了这个属性,于是会产生不必要的更新,最好的方式是把数据统一放到Store中,子组件通过 inject store 方式获取数据。

小组件

由于React的机制,Mobx只能在组件层发光发热,对于组件内部就是无能为力了,所以大组件很容易卡死,小组件才能真正发挥Mobx的优势。

在专用组件中渲染列表

React在渲染大型数据集合的时候处理的很不好,因为协调器必须评估每个集合变化的集合所产生的组件。因此,建议使用专门的组件来映射集合并渲染这个组件,且不再渲染其他组件:

官方提供的demo如下:

不妥的处理方式:

@observer class MyComponent extends Component {render() {const {todos, user} = this.props;return (<div>{user.name}<ul>{todos.map(todo => <TodoView todo={todo} key={todo.id} />)}</ul></div>)}
}

在示例中,当user.name发生变化时React 会不必要地协调所有的 TodoView 组件。尽管TodoView 组件不会重新渲染,但是协调的过程本身是非常昂贵的。

正确的处理方式:

@observer class MyComponent extends Component {render() {const {todos, user} = this.props;return (<div>{user.name}<TodosView todos={todos} /></div>)}
}@observer class TodosView extends Component {render() {const {todos} = this.props;return <ul>{todos.map(todo => <TodoView todo={todo} key={todo.id} />)}</ul>)}
}

在react-native使用Mobx常见的问题

observable 数组的类型是对象

observable 数组类型其实是个对象,所以它遵循propTypes.object ,如果使用propTypes.array 会报错。mobx-react 为 observable 数据结构提供了明确的 PropTypes。

在 React Native 中渲染 ListView

React Native 的的DataSource只能接收真正的数组,但是observable 数组是个对象,所以在传给ListView之前使用.slice方法,此外,ListView.DataSource 本身可以移到 store 之中并且使用 @computed 自动地更新,这步操作同样可以在组件层完成

class ListStore {@observable list = ['Hello World!','Hello React Native!','Hello MobX!'];ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });@computed get dataSource() {return this.ds.cloneWithRows(this.list.slice());}
}const listStore = new ListStore();@observer class List extends Component {render() {return (<ListViewdataSource={listStore.dataSource}renderRow={row => <Text>{row}</Text>}enableEmptySections={true}/>);}
}

原文http://techblog.sishuxuefu.com/atricle.html?5bb9f17a0b6160006f5988bb

这篇关于强大的状态管理工具-Mobx的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/509253

相关文章

关于WebSocket协议状态码解析

《关于WebSocket协议状态码解析》:本文主要介绍关于WebSocket协议状态码的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录WebSocket协议状态码解析1. 引言2. WebSocket协议状态码概述3. WebSocket协议状态码详解3

Flutter监听当前页面可见与隐藏状态的代码详解

《Flutter监听当前页面可见与隐藏状态的代码详解》文章介绍了如何在Flutter中使用路由观察者来监听应用进入前台或后台状态以及页面的显示和隐藏,并通过代码示例讲解的非常详细,需要的朋友可以参考下... flutter 可以监听 app 进入前台还是后台状态,也可以监听当http://www.cppcn

使用Go语言开发一个命令行文件管理工具

《使用Go语言开发一个命令行文件管理工具》这篇文章主要为大家详细介绍了如何使用Go语言开发一款命令行文件管理工具,支持批量重命名,删除,创建,移动文件,需要的小伙伴可以了解下... 目录一、工具功能一览二、核心代码解析1. 主程序结构2. 批量重命名3. 批量删除4. 创建文件/目录5. 批量移动三、如何安

MySQL 中的服务器配置和状态详解(MySQL Server Configuration and Status)

《MySQL中的服务器配置和状态详解(MySQLServerConfigurationandStatus)》MySQL服务器配置和状态设置包括服务器选项、系统变量和状态变量三个方面,可以通过... 目录mysql 之服务器配置和状态1 MySQL 架构和性能优化1.1 服务器配置和状态1.1.1 服务器选项

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例

通过prometheus监控Tomcat运行状态的操作流程

《通过prometheus监控Tomcat运行状态的操作流程》文章介绍了如何安装和配置Tomcat,并使用Prometheus和TomcatExporter来监控Tomcat的运行状态,文章详细讲解了... 目录Tomcat安装配置以及prometheus监控Tomcat一. 安装并配置tomcat1、安装

Linux之进程状态&&进程优先级详解

《Linux之进程状态&&进程优先级详解》文章介绍了操作系统中进程的状态,包括运行状态、阻塞状态和挂起状态,并详细解释了Linux下进程的具体状态及其管理,此外,文章还讨论了进程的优先级、查看和修改进... 目录一、操作系统的进程状态1.1运行状态1.2阻塞状态1.3挂起二、linux下具体的状态三、进程的

Rsnapshot怎么用? 基于Rsync的强大Linux备份工具使用指南

《Rsnapshot怎么用?基于Rsync的强大Linux备份工具使用指南》Rsnapshot不仅可以备份本地文件,还能通过SSH备份远程文件,接下来详细介绍如何安装、配置和使用Rsnaps... Rsnapshot 是一款开源的文件系统快照工具。它结合了 Rsync 和 SSH 的能力,可以帮助你在 li

python管理工具之conda安装部署及使用详解

《python管理工具之conda安装部署及使用详解》这篇文章详细介绍了如何安装和使用conda来管理Python环境,它涵盖了从安装部署、镜像源配置到具体的conda使用方法,包括创建、激活、安装包... 目录pytpshheraerUhon管理工具:conda部署+使用一、安装部署1、 下载2、 安装3