LoginSignup
5
2

More than 5 years have passed since last update.

Mobx で管理されたステートを FlatList に渡す時は .slice() する

Last updated at Posted at 2018-01-18

背景

Mobx で管理されたローカルなステートを React Native の FlatList に渡す時に、下記のWarningが出て困った

[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

この原因は、MobXの @observable デコレーターで定義された配列は、JSの Array ではなく、 MobXの ObservableArray になるため、 ListView, FlatList, SectionList などが解釈できない形になっているらしい。

なので、 ObservableArray.toJS あるいは .slice() メソッドでJSの Array に変換してあげれば良い。

// @flow

import React from 'react'
import { observable } from 'mobx'
import { FlatList, Text } from 'react-native'
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} とするとエラーを吐く
      data={this.users.slice()}
    />
  }
}

追記

Warningが出ない場合でも、再描画されない場合があるので、 .slice() した方が良さげ。
特に、空の配列に要素を追加した時や、オブジェクトの配列でそのオブジェクトの一部を変更した、みたいな場合に再描画されない。

.slice() しなくて良い場合もある。逆に常に .slice() していると、パフォーマンスに影響がありそう。
個人的には、リアクティブに再描画されない問題が起こると原因追求が難しいので、多少のパフォーマンスを犠牲にしても .slice() してしまっている。
Storeのユニットテストだけは書いておいた。

どんな場合に再描画されないのか、ちゃんと調べたい。

参考

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2