前言

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相关推荐

  1. Mobx | 强大的状态管理工具 | 可以用Mobx来替代掉redux

    来源简书 电梯直达 https://www.jianshu.com/p/505d9d9fe36a Mobx是一个功能强大,上手非常容易的状态管理工具.就连redux的作者也曾经向大家推荐过它,在不少情 ...

  2. [译] ⚛ React 状态管理工具博物馆

    原文地址:⚛ The React State Museum: ⚡️View the hottest state management libs for React 原文作者:Gant Laborde ...

  3. 浅析前端状态管理Redux Mobx Vuex

    写在前面 前端技术的发展日新月异,vue,react,angular等的兴起,为我们带来了新的开发体验.但随着技术的革新,以及前端页面复杂度的提升,对应有localStorage,eventBus,v ...

  4. 可能是基于 Hooks 和 Typescript 最好的状态管理工具

    接上一篇:我理想中的状态管理工具 之前说,对于我个人来而言,理想的状态管理工具只需同时满足两个特点: 简单易用,并且适合中大型项目 完美地支持 Typescript 未能找到一个完美满足这两点的,所以 ...

  5. 状态管理 - 全局状态管理工具

    文章目录 一.单向数据流 1. 理念示意图 2. 简述 二.什么是全局状态管理模式 三.重点概念 3.1. 什么是全局状态管理模式? 3.2.全局状态管理工具? 3.3. 什么是 vuex 四.在项目 ...

  6. Vue新一代状态管理工具—Pinia—都2023年了,快学起来吧!

    Pinia 基本介绍 Pinia 是 Vue.js 的轻量级状态管理库 官方网站:https://pinia.vuejs.org/ 中文文档: https://pinia.web3doc.top/in ...

  7. vue3状态管理工具 pinia的使用

    vue3状态管理工具 pinia的使用 pinia 是一个轻量级的状态管理库,属于 vue3 生态圈新的成员之一,也可以把它看做 vuex5,同时支持 vue2 和 vue3,模块化的设计让它的结构十 ...

  8. 从收集到输出:盘点那些强大的知识管理工具——优秀笔记软件盘点

    从收集到输出:盘点那些强大的知识管理工具--优秀笔记软件盘点(四) 只推荐优质.强大的生产力工具 在以往的文章中,我已经介绍了不少兼具优雅和强大等特性的工具.今天我将围绕知识管理主题,我将从信息收集到 ...

  9. Lattics ——一款简单易用、好看强大的知识管理工具

    如何选择一款适合自己的知识管理工具? 对于很多用户而言,在追求效率的路上,经常需要一款适合自己的知识管理工具.然而,随着工具市场的发展,各种新兴工具层出不穷.在传统领域,有印象笔记.Onenote 为 ...

最新文章

  1. mongodb与java连接_MongoDBJava连接
  2. 洛谷 1563 玩具谜题——模拟水题
  3. 并查集算法学习(转)
  4. Python中函数的用法
  5. 阶段3 3.SpringMVC·_07.SSM整合案例_04.ssm整合之编写SpringMVC框架
  6. python爬取genek视频_【Python】爬虫(Xpath):批量爬取站长免费简历
  7. 处女座的砝码-数学推论
  8. NVMe PM951 硬盘写入速度优化
  9. 最适合游戏的显卡排行榜,显卡天梯图
  10. java 什么是成员变量_java成员变量和方法的含义是什么?异同点有哪些?
  11. SpringBoot的报错找不到Mapper(解决:required a bean of type com.xxx.mapper.UserMapper that could not be found)
  12. 贪吃的九头龙-----树形dp
  13. JavaScript百炼成仙 1.20 函数七重关之二 (作用域)
  14. 【工具-AWVS】AWVS安装与使用
  15. JESD204协议理解
  16. css px em rem % vw vh vm 区别
  17. 交通灯控制器的verilog实现
  18. 程序员也可以抒情写诗
  19. 【PHP】php 源码之宏 PHP_FUNCTION
  20. 华氏摄氏温度转换问题(C语言程序设计)

热门文章

  1. 滑模变结构控制的几种切换函数
  2. 计算机病毒级防范措施总结,计算机病毒论文总结
  3. 美团面试,360面试 ,滴滴面试,阿里面试,百度面试,京东面试,搜狗面试:
  4. 【方案搭建】住建局建筑工地联合GB28181视频平台EasyGBS搭建千里眼视频监控方案
  5. web安全工具库(笔记)----端口扫描(SuperScanV4.0-RHC.exe)
  6. 黑鲨5Pro国际版发布时间曝光 将于6月8日发布
  7. 华为鸿蒙的科技话题作文800字,科技的发展作文800字4篇
  8. 用Video Proc来进行修剪视频
  9. 4G/5G多卡聚合设备为应急通信行业提供网络解决方案
  10. sql查询出两张表id不同的数据