title: 使用 MobX
自
1.2.0-beta.1开始支持
MobX 为复杂项目中状态管理提供了一种简单高效的机制;Taro 提供了 @tarojs/mobx 来让开发人员在使用 MobX 的过程中获得更加良好的开发体验。
安装
$ yarn add mobx@4.8.0 @tarojs/mobx @tarojs/mobx-h5 @tarojs/mobx-rn# 或者使用 npm$ npm install --save mobx@4.8.0 @tarojs/mobx @tarojs/mobx-h5 @tarojs/mobx-rn
API
onError
Mobx 异常监听。
import { onError } from '@tarojs/mobx'onError(error => {console.log('mobx global error listener:', error)})
isUsingStaticRendering
自
1.3.6开始支持
判断是否开启了服务端渲染(该状态为全局状态)。
import { isUsingStaticRendering } from '@tarojs/mobx'if (isUsingStaticRendering()) {//...}
useStaticRendering
自
1.3.6开始支持
服务端渲染状态设置(该状态为全局状态)。
import { useStaticRendering } from '@tarojs/mobx'useStaticRendering(false)
useLocalStore
自
1.3.6开始支持
将对象转换为 observable 对象,其中 getter 会被转换为 computed 属性,方法会与 store 进行绑定并自动执行
mobx transactions,比如:
import Taro from '@tarojs/taro'import { View, Text, Button } from '@tarojs/components'import { useLocalStore, observer } from '@tarojs/mobx'import './index.scss'function Index() {const store = useLocalStore(() => ({counter: 0,increment() {store.counter++},decrement() {store.counter--},incrementAsync() {setTimeout(() => store.counter++, 1000)}}))const { counter, increment, decrement, incrementAsync } = store;return (<View><Button onClick={increment}>+</Button><Button onClick={decrement}>-</Button><Button onClick={incrementAsync}>Add Async</Button><Text>{counter}</Text></View>)}export default observer(Index)
useAsObservableSource
自
1.3.6开始支持
与 useLocalStore 的区别是,它将纯(不包含 getter 或方法)对象转换为 observable,主要使用场景为:
- 如果对象某个属性的值需经过复杂运算才能获得,可通过该方法进行包装,这样在组件的生命周期中该运算只需要运算一次。
一般情况下
useLocalStore仅用于组件内部,如果useLocalStore中的对象需要依赖外部传递的属性,那么可通过useAsObservableSource将这些属性进行转换,而后在useLocalStore对象中进行引用,这样在外部属性改变时自动通知useLocalStore对象对变化进行响应,比如:import Taro from '@tarojs/taro'import { View, Button, Text } from '@tarojs/components'import { useAsObservableSource, useLocalStore, observer } from '@tarojs/mobx'function Multiplier(props) {const observableProps = useAsObservableSource(props)const store = useLocalStore(() => ({counter: 1,get multiplied() {return observableProps.multiplier * store.counter},increment() {store.counter += 1}}))const { multiplier } = observablePropsconst { multiplied, counter, increment } = storereturn (<View><Text>multiplier({multiplier}) * counter({counter}) = {multiplied}</Text><Button onClick={increment}>Increment Counter</Button></View>)}export default observer(Multiplier)
该场景也可直接使用
useLocalStore中的第二种用法来实现:import Taro from '@tarojs/taro'import { View, Button, Text } from '@tarojs/components'import { useLocalStore, observer } from '@tarojs/mobx'function Multiplier(props) {const store = useLocalStore(source => ({counter: 1,get multiplier() {return source.multiplier},get multiplied() {return source.multiplier * store.counter},increment() {store.counter += 1}}), props)const { multiplied, counter, increment, multiplier } = storereturn (<View><Text>multiplier({multiplier}) * counter({counter}) = {multiplied}</Text><Button onClick={increment}>Increment Counter</Button></View>)}export default observer(Multiplier)
observer
将组件设置为监听者,以便在可观察对象的值改变后触发页面的重新渲染。
注:
不要在
JSX中对可观察对象进行引用,比如:// 错误,在小程序中值改变后将无法触发重新渲染const { counterStore } = this.propsreturn (<Text>{counterStore.counter}</Text>)// 正确const { counterStore: { counter } } = this.propsreturn (<Text>{counter}</Text>)
这是因为
@tarojs/mobx通过监听组件的render(小程序编译后为_createData)方法来触发更新;在小程序中,JSX的代码会被编译到wxml文件中,此时对可观察对象的引用(比如:counterStore.counter)早已脱离了@tarojs/mobx的监控,故此对该属性的更改并不会触发更新操作。如使用
@observable装饰器来定义可观察对象时,请确保该属性已经初始化,比如:@observable counter // 错误,值改变后将无法触发重新渲染@observable counter = 0 // 正确
如果
isUsingStaticRendering为true,该方法不做任何事情。
Provider
全局 store 设置,比如:
import Taro, { Component } from '@tarojs/taro'import { Provider } from '@tarojs/mobx'import Index from './pages/index'import counterStore from './store/counter'const store = {counterStore}class App extends Component {config = {pages: ['pages/index/index'],window: {backgroundTextStyle: 'light',navigationBarBackgroundColor: '#fff',navigationBarTitleText: 'WeChat',navigationBarTextStyle: 'black'}}render () {return (<Provider store={store}><Index /></Provider>)}}Taro.render(<App />, document.getElementById('app'))
注:
Provider必须作用于入口文件(即:src/app.js),在其他地方使用无效。- 不支持嵌套,即全局只能存在一个
Provider。 在
mobx-react中,可通过以下方式设置store:<Provider store1={xxxx} store2={xxxx}><XXX /></Provider>
而在
@tarojs/mobx中,我们需要使用以下方式设置:const store = {store1: xxxx,store2: xxxx}<Provider store={store}><XXX /></Provider>
inject
将 Provider 中设置的 store 提取到组件的 props 中,该 API 只适用于类组件,比如:
import Taro, { Component } from '@tarojs/taro'import { observer, inject } from '@tarojs/mobx'import './index.scss'@inject('counterStore')@observerclass Index extends Component {//...}export default Index
或
import Taro, { Component } from '@tarojs/taro'import { observer, inject } from '@tarojs/mobx'import './index.scss'@inject((stores, props) => ({counterStore: stores.counterStore}))@observerclass Index extends Component {//...}export default Index
注:
- 无论以何种方式使用
inject,其后的observer均不能省略。 不要在
inject中引用可观察对象,这将导致属性改变后页面不更新,比如:// 错误@inject((stores, props) => ({counter: stores.counterStore.counter}))// 正确@inject((stores, props) => ({counterStore: stores.counterStore}))
PropTypes
自
1.3.6开始支持
@tarojs/mobx 提供了以下 PropTypes 来验证 Mobx 的结构:
- observableArray
- observableArrayOf
- observableMap
- observableObject
- arrayOrObservableArray
- arrayOrObservableArrayOf
- objectOrObservableObject
