使用 MobX

1.2.0-beta.1 开始支持

MobX 为复杂项目中状态管理提供了一种简单高效的机制;Taro 提供了 @tarojs/mobx 来让开发人员在使用 MobX 的过程中获得更加良好的开发体验。

安装

  1. $ yarn add mobx@4.8.0@tarojs/mobx @tarojs/mobx-h5 @tarojs/mobx-rn
  2. # 或者使用 npm
  3. $ npm install --save mobx@4.8.0@tarojs/mobx @tarojs/mobx-h5 @tarojs/mobx-rn

API

onError

Mobx 异常监听。

  1. import{ onError }from'@tarojs/mobx'
  2. onError(error =>{
  3. console.log('mobx global error listener:', error)
  4. })

isUsingStaticRendering

1.3.6 开始支持

判断是否开启了服务端渲染(该状态为全局状态)。

  1. import{ isUsingStaticRendering }from'@tarojs/mobx'
  2. if(isUsingStaticRendering()){
  3. //...
  4. }

useStaticRendering

1.3.6 开始支持

服务端渲染状态设置(该状态为全局状态)。

  1. import{ useStaticRendering }from'@tarojs/mobx'
  2. useStaticRendering(false)

useLocalStore

1.3.6 开始支持

将对象转换为 observable 对象,其中 getter 会被转换为 computed 属性,方法会与 store 进行绑定并自动执行mobx transactions,比如:

  1. importTarofrom'@tarojs/taro'
  2. import{View,Text,Button}from'@tarojs/components'
  3. import{ useLocalStore, observer }from'@tarojs/mobx'
  4. import'./index.scss'
  5. functionIndex(){
  6. const store = useLocalStore(()=>({
  7. counter:0,
  8. increment(){
  9. store.counter++
  10. },
  11. decrement(){
  12. store.counter--
  13. },
  14. incrementAsync(){
  15. setTimeout(()=> store.counter++,1000)
  16. }
  17. }))
  18. const{ counter, increment, decrement, incrementAsync }= store;
  19. return(
  20. <View>
  21. <Button onClick={increment}>+</Button>
  22. <Button onClick={decrement}>-</Button>
  23. <Button onClick={incrementAsync}>AddAsync</Button>
  24. <Text>{counter}</Text>
  25. </View>
  26. )
  27. }
  28. exportdefault observer(Index)

useAsObservableSource

1.3.6 开始支持

useLocalStore 的区别是,它将纯(不包含 getter 或方法)对象转换为 observable,主要使用场景为:

  • 如果对象某个属性的值需经过复杂运算才能获得,可通过该方法进行包装,这样在组件的生命周期中该运算只需要运算一次。

  • 一般情况下 useLocalStore 仅用于组件内部,如果 useLocalStore 中的对象需要依赖外部传递的属性,那么可通过useAsObservableSource 将这些属性进行转换,而后在 useLocalStore 对象中进行引用,这样在外部属性改变时自动通知useLocalStore 对象对变化进行响应,比如:

  1. importTarofrom'@tarojs/taro'
  2. import{View,Button,Text}from'@tarojs/components'
  3. import{ useAsObservableSource, useLocalStore, observer }from'@tarojs/mobx'
  4. functionMultiplier(props){
  5. const observableProps = useAsObservableSource(props)
  6. const store = useLocalStore(()=>({
  7. counter:1,
  8. get multiplied(){
  9. return observableProps.multiplier * store.counter
  10. },
  11. increment(){
  12. store.counter +=1
  13. }
  14. }))
  15. const{ multiplier }= observableProps
  16. const{ multiplied, counter, increment }= store
  17. return(
  18. <View>
  19. <Text>multiplier({multiplier})* counter({counter})={multiplied}</Text>
  20. <Button onClick={increment}>IncrementCounter</Button>
  21. </View>
  22. )
  23. }
  24. exportdefault observer(Multiplier)

该场景也可直接使用 useLocalStore 中的第二种用法来实现:

  1. importTarofrom'@tarojs/taro'
  2. import{View,Button,Text}from'@tarojs/components'
  3. import{ useLocalStore, observer }from'@tarojs/mobx'
  4. functionMultiplier(props){
  5. const store = useLocalStore(source =>({
  6. counter:1,
  7. get multiplier(){
  8. return source.multiplier
  9. },
  10. get multiplied(){
  11. return source.multiplier * store.counter
  12. },
  13. increment(){
  14. store.counter +=1
  15. }
  16. }), props)
  17. const{ multiplied, counter, increment, multiplier }= store
  18. return(
  19. <View>
  20. <Text>multiplier({multiplier})* counter({counter})={multiplied}</Text>
  21. <Button onClick={increment}>IncrementCounter</Button>
  22. </View>
  23. )
  24. }
  25. exportdefault observer(Multiplier)

observer

将组件设置为监听者,以便在可观察对象的值改变后触发页面的重新渲染。

注:

  • 不要在 JSX 中对可观察对象进行引用,比如:
  1. // 错误,在小程序中值改变后将无法触发重新渲染
  2. const{ counterStore }=this.props
  3. return(
  4. <Text>{counterStore.counter}</Text>
  5. )
  6. // 正确
  7. const{ counterStore:{ counter }}=this.props
  8. return(
  9. <Text>{counter}</Text>
  10. )

这是因为 @tarojs/mobx 通过监听组件的 render(小程序编译后为 _createData)方法来触发更新;在小程序中,JSX的代码会被编译到 wxml 文件中,此时对可观察对象的引用(比如:counterStore.counter)早已脱离了@tarojs/mobx 的监控,故此对该属性的更改并不会触发更新操作。

  • 如使用 @observable 装饰器来定义可观察对象时,请确保该属性已经初始化,比如:
  1. @observable counter // 错误,值改变后将无法触发重新渲染
  2. @observable counter =0// 正确
  • 如果 isUsingStaticRenderingtrue,该方法不做任何事情。

Provider

全局 store 设置,比如:

  1. importTaro,{Component}from'@tarojs/taro'
  2. import{Provider}from'@tarojs/mobx'
  3. importIndexfrom'./pages/index'
  4. import counterStore from'./store/counter'
  5. const store ={
  6. counterStore
  7. }
  8. classAppextendsComponent{
  9. config ={
  10. pages:[
  11. 'pages/index/index'
  12. ],
  13. window:{
  14. backgroundTextStyle:'light',
  15. navigationBarBackgroundColor:'#fff',
  16. navigationBarTitleText:'WeChat',
  17. navigationBarTextStyle:'black'
  18. }
  19. }
  20. render (){
  21. return(
  22. <Provider store={store}>
  23. <Index/>
  24. </Provider>
  25. )
  26. }
  27. }
  28. Taro.render(<App/>, document.getElementById('app'))

注:

  • Provider 必须作用于入口文件(即:src/app.js),在其他地方使用无效。

  • 不支持嵌套,即全局只能存在一个 Provider

  • mobx-react 中,可通过以下方式设置 store

  1. <Providerstore1={xxxx}store2={xxxx}>
  2. <XXX/>
  3. </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')
@observer
class 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
}))
@observer
class 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

资源

示例:taro-mobx-sample