LoginSignup
22
9

More than 5 years have passed since last update.

React Native の ListView でつまづきがちなこと

Last updated at Posted at 2016-12-05

React Nativeでリスト構造のビューを実装する際、基本的には ListView を使います。
使っている中で地味につまづきがちなところを、今回は紹介したいと思います。

表示が遅い

少ない件数を扱っているときには気になりませんが、100件とかを一気に表示しようとすると、下記のような問題が起きてきます。

  • 1行ずつパラパラと描画される
  • 操作がブロックされてしまうため、レンダリングが終わるまで他のアクションが動作しない

パフォーマンスの改善には下記のプロパティを使うことができます。

プロパティ 説明 デフォルト
initialListSize 初期レンダリングする行数を指定。 10
pageSize initialListSize で指定した行数の初期レンダリング後、一度にレンダリングする行数を指定。 1
scrollRenderAheadDistance スクロールが発生する場合、先読みで行のレンダリングをしておく範囲をピクセル数で指定。 1000

pageSize のデフォルトが 1 なので、1行ごとにレンダリングされてパラパラと表示されていたんですね。
initialListSizepageSize に適切な数値を設定してレンダリングの回数を減らすだけでも、表示速度はかなり改善できます。
scrollRenderAheadDistance は他と比べて調整しても効果を実感しにくいかもです。
数値の最適化は、動かしながら調整してみましょう。

リストに追加できない

下記のようにリストを定義しているとき、みなさんだったら、後からリストに要素を追加する関数をどのように実装するでしょうか。

constructor() {
  this.rawArray = [
    { id: 1 },
    { id: 2 },
  ];
  this.state = {
    dataSource: ds.cloneWithRows(this.rawArray),
  };
}

大体の方は、まず下記のように実装するのではないかと思います。

// NGパターン
addItem(item) {
  const {rawArray} = this;
  rawArray.push(item);
  this.setState({
    dataSource: ds.cloneWithRows(rawArray),
  });
}

これだとリストが再評価されず、表示に反映されません。
再評価させるためには、リストのインスタンスを新たに作り、cloneWithRows に渡す必要があります。

// OKパターン
addItem(item) {
  const newArray = this.rawArray.slice(); // ここ注目。シャローコピーしている
  newArray.push(item);
  this.setState({
    dataSource: ds.cloneWithRows(newArray),
  });
  this.rawArray = newArray;
}

これで表示に反映されます。
リスト要素の更新や、削除の場合にも同様の実装が必要なので要注意です。

参考

https://facebook.github.io/react-native/docs/performance.html#listview-initial-rendering-is-too-slow-or-scroll-performance-is-bad-for-large-lists
https://github.com/facebook/react-native/issues/4104

22
9
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
22
9