【React Native】画像リストが重い・落ちる?「expo-image」で爆速キャッシュ化する方法

エンジニアの記録
技術メモ・実体験

画像を多く表示する画面で、スクロールがカクつく・画像がちらつく・端末によってはメモリ不足で落ちる。標準のImageのまま大量画像を扱うと起きがちです。

この記事でわかること

expo-imageに置き換えてキャッシュとプレースホルダーを正しく設定し、画像表示を速く・安定させる方法をコードつきで書きます。

PROFILE 20代ITエンジニア|React Native(Expo)× AWS Amplifyでアプリ開発中|Raw Ambition 運営
キラ
キラ
標準のImageはキャッシュ制御が弱い。画像が主役の画面なら、まずexpo-imageに替えるのが定石。
Contents
  1. 結論:expo-imageに替えてキャッシュを効かせる
  2. なぜ標準Imageだと重い・落ちるのか
  3. 基本の置き換えとcachePolicy
  4. ちらつきを消すplaceholderとtransition
  5. リストで使うときの注意
  6. まとめ
結論:expo-imageに替えてキャッシュを効かせる

結論です。画像が多い画面なら標準のImageexpo-imageに置き換え、cachePolicyplaceholderを設定する。これでカクつき・ちらつき・再ダウンロードの大半が解消します。

# インストール
npx expo install expo-image
なぜ標準Imageだと重い・落ちるのか

理由は主に2つです。

? 標準Imageで起きること

① キャッシュ制御が弱い
   → 同じ画像でも画面を戻るたびに再ダウンロード
   → リストをスクロールするたびネットワーク負荷

② 巨大画像をそのまま展開する
   → サーバーが4000pxの写真を返すと
     表示は100pxでもメモリには4000px分が載る
   → 大量に並ぶとメモリ不足でクラッシュ

expo-imageはディスク+メモリの二段キャッシュを持ち、デコードも効率的なので、この2つの問題に強いです。

基本の置き換えとcachePolicy

importを差し替え、resizeModecontentFitに直すのが基本です。

// ❌ Before
import { Image } from 'react-native';
<Image source={{ uri }} style={s} resizeMode="cover" />

// ✅ After
import { Image } from 'expo-image';
<Image
  source={{ uri }}
  style={s}
  contentFit="cover"
  cachePolicy="memory-disk"
/>

? POINT

cachePolicy="memory-disk"はメモリとディスク両方にキャッシュします。一度読んだ画像は次回以降ダウンロードしないので、戻る操作やリストの再スクロールが一気に速くなります。
ちらつきを消すplaceholderとtransition

読み込み中に何も出ないと、画像が後からポンと出て「ちらつき」に見えます。placeholder(blurhashなど)とtransitionでなめらかにします。

<Image
  source={{ uri }}
  style={s}
  contentFit="cover"
  cachePolicy="memory-disk"
  placeholder={{ blurhash: 'L6Pj0^jE.AyE_3t7t7R**0o#DgR4' }}
  transition={200}
/>

blurhashが用意できなければ、単色のプレースホルダーでも体感はかなり良くなります。

スカイ
スカイ
placeholderを置くだけで「ちゃんと作ってるアプリ」っぽさが出るよね。地味だけど効く。
リストで使うときの注意

FlatListはセルを使い回すため、スクロール中に前の画像が一瞬残ることがあります。recyclingKeyに一意な値を渡すと、使い回し時に画像をリセットできます。

<Image
  source={{ uri: item.imageUrl }}
  style={s}
  contentFit="cover"
  cachePolicy="memory-disk"
  recyclingKey={item.id}   // セル使い回し時に前画像を残さない
/>

⚠️ 注意

根本的にメモリが厳しいなら、サーバー側でサムネイルを返すのが最善です。一覧は小さい画像、詳細でフル解像度、という出し分けがクラッシュ対策として一番効きます。

? この記事のまとめ
  • 画像が多い画面はexpo-imageへ置き換える
  • cachePolicy=”memory-disk”で再ダウンロードを止める
  • placeholder + transitionでちらつきを消す
  • リストではrecyclingKey、根本対策はサーバー側サムネイル
Recommended
学んだことは、ブログに書くと一番定着する
エンジニアのアウトプット先として、表示速度の速いConoHa WINGでブログを始めました。月額わずか、最短10分で開設できます。
▶ ConoHa WINGでブログを始める
※ アフィリエイトリンクです
Next
次回:React NavigationをTypeScriptで型安全にする
React Native実践シリーズ

コメント

タイトルとURLをコピーしました