MobX 是一款十分優秀的狀態管理庫,不但書寫簡潔還很是高效。固然這是我在使用以後才體會到的,當初試水上車的主要緣由是響應式,考慮到可能會更符合 Vue 過來的思考方式。然而其實二者除了響應式之外並無什麼類似之處。javascript
在使用過程當中走了很多彎路,一部分是由於當時掃兩眼文檔就動手,對 MobX 機制理解得不夠;其它緣由是 MobX 終究只是一個庫,會受限於 React 機制,以及與其它非 MobX 管理組件的兼容問題。當中不少狀況在文檔已經給出了說明(這裏和這裏),我根據本身遇到的再作一番總結。html
與非響應式的組件一塊兒工做時,MobX 有時須要爲它們提供一份非響應式的數據副本,以避免 observable 被其它組件修改。java
使用 React Navigation 導航時,若是要交由 MobX 管理,則須要手動配置導航狀態棧,此時用 @observable.ref
「淺觀察」可避免狀態被 React Navigation 修改時觸發 MobX 警告。react
當 Navigator 接受 navigation
props 時表明導航狀態爲手動管理。react-native
import { addNavigationHelpers, StackNavigator } from 'react-navigation' import { observable, action } from 'mobx' import { Provider, observer } from 'mobx-react' import AppComp from './AppComp' const AppNavigator = StackNavigator({ App: { screen: AppComp }, // ... }, { initialRouteName: 'App', headerMode: 'none' }) @observer export default class AppNavigation extends Component { @observable.ref navigationState = { index: 0, routes: [ { key: 'App', routeName: 'App' } ], } @action.bound dispatchNavigation = (action, stackNavState = true) => { const previousNavState = stackNavState ? this.navigationState : null this.navigationState = this.AppNavigator.router.getStateForAction(action, previousNavState) return this.navigationState } render () { return ( <Provider dispatchNavigation={this.dispatchNavigation} navigationState={this.navigationState} > <AppNavigator navigation={addNavigationHelpers({ dispatch: this.dispatchNavigation, state: this.navigationState, })} /> </Provider> ) } }
observable.shallowArray()
與 observable.shallowMap()
MobX 還提供其它方便的數據結構來存放非響應式數據。數組
好比使用 SectionList
的時候,咱們要爲其提供數據用於生成列表,因爲 Native 官方的實現跟 MobX 不兼容,這個數據不能是響應式的,否則 MobX 會報一堆警告。緩存
MobX 有個 mobx.toJS()
方法能夠導出非響應式副本;若是結構不相同還可使用 @computed
自動生成符合的數據。但這兩個方法每次添加項目都要所有遍歷一遍,可能會存在性能問題。數據結構
這時其實能夠維護一個 observable.shallowArray
,裏面只放 key
數據,只用於生成列表(像骨架同樣)。傳給 SectionList
的 sections
props 時 slice
數組複製副本(shallowArray 裏的數據非響應式,因此只需淺複製,複雜度遠小於上面兩種方式)。app
而後 store 維護一個 observable.map
來存放每一個項的數據,在項(item)組件中 inject
store 進去,再利用 key
從 map 中獲取數據來填充。ide
經過 shallowArray 可讓 MobX 識別列表長度變化自動更新列表,利用 map 維護項數據可使每一個項保持響應式卻互不影響,對長列表優化效果很明顯。
// store comp class MyStore { @observable sections = observable.shallowArray() @observable itemData = observable.map() @action.bound appendSection (section) { const data = [] section.items.forEach(action(item => { this.itemData.set(item.id, item) data.push({key: item.id}) })) this.sections.push({ key: section.id, data }) } }
// MyList comp import { SectionList } from 'react-native' @inject('myStore') @observer class MyList extends React.Component { _renderItem = ({item}) => <SectionItem id={item.key} /> render () { return ( <SectionList getItemLayout={this._getItemLayout} sections={this.props.myStore.sections.slice()} renderSectionHeader={this._renderSectionHeader} renderItem={this._renderItem} /> ) } }
// SectionItem comp @inject('myStore') @observer class SectionItem extends React.Component { render () { const {myStore, id} = this.props const itemData = myStore.itemData.get(id) return ( <Text>{itemData.title}</Text> ) } }
利用 @computed
緩存數據能夠作一些優化。
好比有一個響應式的數組 arr
,一個組件要根據 arr
是否爲空更新。若是直接訪問 arr.length
,那麼只要數組長度發生變化,這個組件都要 render 一遍。
此時利用 computed 生成,組件只須要判斷 isArrEmpty
就能夠減小沒必要要的更新:
@computed get isArrEmpty () { return this.arr.length <= 0 }
因 JS 機制 MobX 不能檢測屬性的增刪,因此最好用 observable.map
取代簡單 {}
對象。另外 MobX 沒有提供 Set 支持,能夠用 key 和 value 同樣的 Map 代替。
這條規則在文檔也提到,緣由很簡單,MobX 對於一個 observer
組件,是經過訪問屬性來記錄依賴的。因此哪怕父組件裏沒有用到這個屬性,只是爲了做爲 props 傳給子組件,MobX 仍是算它依賴了這個屬性,因而會產生沒必要要的更新。最好的方式是將數據統一放在 store 中,子組件經過 inject
store 方式獲取數據。
因爲 React 的機制,MobX 只能在組件層面發光發熱,對於組件內部就無能爲力了。因此大組件用 MobX 很容易卡死(用其它也會),小組件才能真正發揮 MobX 自動管理更新的優點。
博客連接:https://blog.crimx.com/2017/1...
【完】