はじめに
React Nativeで長いリストを表示していると、スクロール中に一瞬だけ白いセルがちらつく、スクロールがカクつく、といった経験をした方は多いのではないでしょうか。標準のFlatListは手軽に使える反面、アイテム数が増えたりレイアウトが複雑になったりすると、パフォーマンスの限界が見えてきます。
この課題に正面から取り組んだのが、Shopifyが開発したFlashListです。「No more blank cells.」というキャッチコピーの通り、空白セルの発生を抑えつつ、FlatListとほぼ同じ感覚で使えることを目指したライブラリです。この記事では、FlashListの特徴からインストール方法、基本的な使い方、実践的なユースケースまで解説します。
FlashListとは
FlashListは、Shopifyが開発・公開しているReact Native向けの高性能リストコンポーネントです。内部でセルのリサイクリング(再利用)を行うことで、大量データのスクロール時にも滑らかな表示を実現します。最新のFlashList v2ではReact Nativeの新アーキテクチャ(New Architecture)専用に再構築され、ネイティブ依存のないJavaScriptのみの実装になりました。
主な特徴
- セルのリサイクリング - スクロール中にビューを使い回すことで、空白セルの発生やメモリ消費を抑えます
- FlatListからの移行が容易 - 多くの場合、コンポーネント名を
FlatListからFlashListに変えるだけで動作します - サイズ推定が不要(v2) - v1で必要だった
estimatedItemSizeの指定が、v2では不要になりました - Masonryレイアウト対応 - Pinterestのような不揃いなグリッドレイアウトも標準機能で実装できます
- TypeScript対応 - 型定義が同梱されており、型安全にリストを実装できます
インストール
# npm
npm install @shopify/flash-list
# yarn
yarn add @shopify/flash-list
# pnpm
pnpm add @shopify/flash-list
FlashList v2はReact Nativeの新アーキテクチャを前提としています。プロジェクトが新アーキテクチャに対応しているか、事前に確認しておきましょう。Expoを利用している場合は、expo install @shopify/flash-listでバージョンの整合性を保ちながら導入できます。
基本的な使い方
FlatListとほぼ同じAPIで利用できます。まずは最小構成の例です。
import { FlashList } from "@shopify/flash-list";
import { Text, View } from "react-native";
type Item = {
id: string;
title: string;
};
const DATA: Item[] = Array.from({ length: 1000 }, (_, i) => ({
id: String(i),
title: `アイテム ${i + 1}`,
}));
const SimpleList = () => {
return (
<FlashList
data={DATA}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<View style={{ padding: 16 }}>
<Text>{item.title}</Text>
</View>
)}
/>
);
};
export default SimpleList;
FlatListを使ったことがあれば、この時点でほぼ違和感なく書けるはずです。v1ではestimatedItemSize(アイテムの高さの目安)を渡す必要がありましたが、v2ではこの指定が不要になり、より少ないコードで最適なパフォーマンスが得られるようになりました。
実践的なユースケース
画像を含むフィードリスト
SNSアプリのタイムラインのように、画像とテキストが混在するリストでもFlashListは効果を発揮します。
import { FlashList } from "@shopify/flash-list";
import { Image, Text, View } from "react-native";
type Post = {
id: string;
imageUrl: string;
caption: string;
};
const FeedList = ({ posts }: { posts: Post[] }) => {
return (
<FlashList
data={posts}
keyExtractor={(post) => post.id}
renderItem={({ item }) => (
<View style={{ marginBottom: 12 }}>
<Image
source={{ uri: item.imageUrl }}
style={{ width: "100%", height: 240, borderRadius: 8 }}
resizeMode="cover"
/>
<Text style={{ marginTop: 4 }}>{item.caption}</Text>
</View>
)}
/>
);
};
export default FeedList;
Masonryレイアウトでのギャラリー表示
写真の縦横比がバラバラなギャラリーは、MasonryFlashListを使うことで簡単に実装できます。
import { MasonryFlashList } from "@shopify/flash-list";
import { Image } from "react-native";
type Photo = {
id: string;
uri: string;
height: number;
};
const PhotoGallery = ({ photos }: { photos: Photo[] }) => {
return (
<MasonryFlashList
data={photos}
numColumns={2}
keyExtractor={(photo) => photo.id}
renderItem={({ item }) => (
<Image
source={{ uri: item.uri }}
style={{ height: item.height, margin: 4, borderRadius: 8 }}
resizeMode="cover"
/>
)}
/>
);
};
export default PhotoGallery;
不揃いな高さの画像を並べる処理は自前で実装すると意外と手間がかかりますが、FlashListならコンポーネントを切り替えるだけで対応できます。
まとめ
FlashListは、FlatListの使いやすさを保ちながら、大量データのスクロールパフォーマンスを大きく改善できるライブラリです。v2ではサイズ推定の指定も不要になり、導入のハードルはさらに下がりました。すでにFlatListで長いリストを実装していて、スクロールのカクつきや空白セルに悩んでいるなら、コンポーネント名を置き換えるだけで試せるFlashListから最適化を始めてみてはいかがでしょうか。
