本文主要是介绍强大的状态管理工具-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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!