こんにちは!
今回は「React Native(Expo) × Firebase」で画像をキャッシュする方法をについて、お伝えしていきたいと思います。
React Native(Expo)で画像をキャッシュするには「React Native Expo Image Cache」というライブラリを使うのがおすすめです!
本記事では、簡単な使い方と使ってみてよかった点について、書いていきたいと思います。
Contents
React Native Expo Image Cacheの使い方
パッケージをインストール
npmの場合
MacBookPro:~ app$ npm install react-native-expo-image-cache
yarnの場合
MacBookPro:~ app$ yarn add react-native-expo-image-cache
画像をキャッシュする
// 画像パスを保有している任意のファイル
// import文を追加
import {CacheManager} from 'react-native-expo-image-cache';
async function getUserData() {
// uriをfirestoreやその他APIなどから取得
const uri = 'https://.....png';
// awaitをつけるのを忘れずに
const path = await CacheManager.get(uri).getPath();
}
FirestoreのonSnapshotとの組み合わせ例
Firestoreに画像パスを保存する方も多いと思いますので、書き方の例を書いてみます。
(もっといい書き方があればご指摘ください🙇♂️)
// firestoreを使った例
import React, {useState, useEffect} from 'react';
import {CacheManager} from 'react-native-expo-image-cache';
import firebase from '../firebase';
import 'firebase/firestore';
const db = firebase.firestore();
async function getCacheImages(obj) {
const cacheUserData = Object.assign({}, obj);
// オブジェクトのループ
for (const userId of Object.keys(cacheUserData)) {
// パスが空白の場合、cache処理は行わず、空白を設定
cacheUserData[userId] = cacheUserData[userId] ?
await CacheManager.get(cacheUserData[userId]).getPath() : '';
}
return cacheUserData;
}
function getAllUserData() {
// Firestoreのsnapshotで画像パスを取得
db.collection('data')
.where('state', '==', 'alive')
.onSnapshot(async (res) => {
let obj = {};
res.forEach((doc) => {
obj = {...obj, ...doc.data()};
});
// obj = {'user1' : 'https:...image1.png', 'image2' : 'https:...iamge2.png'}
// awaitで呼び出すことで、全てキャッシュ完了後、後続のsetStateが実行されます
const cacheUserData = await getCacheImages(obj);
// 必要に応じて、contextで管理
setState(cacheUserData);
});
}
useEffect(() => {
getAllUserData();
}, []);
キャッシュがちゃんと機能しているか確認
まず、以下のように画像をキャッシュして表示させます
//省略
const path = await CacheManager.get(uri).getPath(); // 処理①
ここで、一度urlの画像を削除してみます。
そしてもう一度、上記の処理①を実行させてみると、ちゃんと画像が表示されているのを確認できました。
このことから、キャッシュする1回目のみurlからダウンロードされることがわかります。
FirebaseのCloud Storage等を使用している場合、ダウンロード量を大幅に減らすことが可能です。
画像をキャッシュすることで、どうだったのか?
画像を全てローカルキャッシュから読み込むことで、画面がチカチカすることがなくなった
1つ目は、外部URLから<image source= {url: https://....} />
のように書くと、画面遷移のたびに画像がチカチカします。
画像機能を実装したことがある方は経験済みかもしれません。。
僕のような神経質な方はとても気になります。笑
キャッシュし、ローカルパスから読み込むことで改善されました。
Firebase FireStorageのダウンロード数(読み取り)が格段に減った
もう1つはFirebase FireStorageのダウンロード数(読み取り)が減り、課金対象のダウンロードの容量が大幅に減った点です。
先ほど説明したように、一度アプリ起動後一度だけダウンロードし、その後はキャッシュから取得します。
画面遷移のたびにダウンロードするのとは何十倍も課金額が変わる可能性があります。
FirestoreのonSnapshotのコールバック処理が重くなった(FireStoreでパスを管理している場合)
僕の場合、FireStoreでパスを管理しており、onSnapshotのコールバック処理で画像をキャッシュするようにしていました。
そのため、更新があるたびに、画像をキャッシュする処理が実行されるので、少し負荷になってしまいました。
他にいい方法があれば、教えてくださいませ🙇♂️