DEV Community

Kay Gosho
Kay Gosho

Posted on

 

To pass MobX's observable array to FlatList, .slice() is needed

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
Enter fullscreen mode Exit fullscreen mode

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> = []
Enter fullscreen mode Exit fullscreen mode

or

users: Array<User> = observable([])
Enter fullscreen mode Exit fullscreen mode

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()}
    />
  }
}
Enter fullscreen mode Exit fullscreen mode

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.

https://stackoverflow.com/questions/44278526/react-native-flatlist-not-rerendering-row-when-props-change

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

Refs:

Top comments (4)

Collapse
 
kmvan profile image
Km.Van

mobxArr.slice() equal toJS(mobxArr) ?

Collapse
 
acro5piano profile image
Kay Gosho • Edited

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!

Collapse
 
zigcccc profile image
Žiga Krašovec

doing [...mobxArr] works as well and it is quite clear & clean in my opinion

Thread Thread
 
acro5piano profile image
Kay Gosho

I think it's up to you.

Top Posts from the React Ecosystem

1. Changes In The Official React Documentation

The former React Docs Beta has been officially released as the updated React documentation at react.dev after years of hard work and refinement. Check out the brand new React Docs: What’s New in the Updated React Docs

2. CRA's Time is Over

React developer team has removed create-react-app (CRA) from official documentation rendering it no longer the default setup method for new projects. The bulky setup, slow, and outdated nature of CRA led to its removal: create-react-app is officially dead

3. How to Fetch Dev.to Articles for Your Portfolio

Integrate the articles of your Dev.to profile into your personal portfolio with either React, Vue, or Next.js by following these simple steps. It outlines how to include frontend to pull the information and correctly utilizes the Dev.to API: How to Fetch Your Dev.to Articles for Your Portfolio with React