A problem happened when using MobX and React Native together.
Problem
I encountered a Warning when I pass MobX's ObservableArray
to FlatList
.
[mobx.array]
Attempt to read an array index(2) that is out of bounds (2).
Please check length first. Out of bound indices will not be tracked by MobX
This may be because FlatList receives array and render lists.
Exact Prop type Array is unexpected for FlatList.
MobX's ObservableArray is defined like this:
@observable users: Array<User> = []
or
users: Array<User> = observable([])
ObservableArray
is not Array
, but ObservableArray behave like native Array so I was confused.
ListView
, SectionList
also regards ObservableArray
as unsuitable prop.
Solution
We can convert ObservableArray
to Array
by .toJS
or .slice()
.
// @flow
import React from 'react'
import { FlatList, Text } from 'react-native'
import { observable } from 'mobx'
import { userApi } from 'app/api'
type User = {
id: number,
name: string
}
class SomeComponent extends React.Component<{}> {
@observable users: Array<User>
componentDidMount() {
userApi.get().then(users => { this.users = users })
}
render() {
<FlatList
keyExtractor={(user) => String(user.id)}
renderItem={({ item }) => <Text>{item.name}</Text> }
// data={this.users} create Warning
data={this.users.slice()}
/>
}
}
Other cases
ObservableArray
and render()
create problems of reactivity.
So if there is no Warning, passing state with .slice()
is a second-good way for preventing unexpected bugs.
Particularly, reactivity problem would happen when we add an element to empty ObservableArray
, or change an attribute of an Object of array.
Sometimes there are no need to .slice()
.
.slice()
cause performance issue so we should not abuse it.
But, in my opinion, reactivity problem is difficult to solve so performance loss is acceptable to some extent.
For prevent further problems, I wrote MobX Store's unit test.
TODO: research and understand when rendering problem happen and not happen
Top comments (4)
mobxArr.slice() equal toJS(mobxArr) ?
As far as I know, they are the same in terms of functionality.
Now I think
toJS
is better because it is more meaningful. Thanks!doing [...mobxArr] works as well and it is quite clear & clean in my opinion
I think it's up to you.