React Nativeの画像キャッシュ
追記 2017-11-27: 結局今はFastImageを使っている。GitHub - DylanVann/react-native-fast-image: 🚩 FastImage, performant React Native image component. 最高。
プロローグ
React Native使ってみた。Image
コンポーネント、毎回ネットワークから取得してるじゃん、これキャッシュしてくれないの?と思った。
調べた
[0.32] Image caching broken · Issue #9581 · facebook/react-native · GitHub
なんか壊れてんヨーという報告を発見。やっぱ壊れてんのかと思いつつ。 でもキャッシュしてもらえる人ともらえない人がいるみたい。日頃のおこない? ちなみに俺はキャッシュしてもらえてない。バージョンは0.38.0で。
なんでやねんと色々思っていると、画像サイズが大きいとダメだというコメントが目に入る。 画像サイズを小さくして試してみる。いけた。600KB -> 178kBぐらいに絞った。
どうやらReact Nativeは画像の取得にiOSに元からあるNSURLRequest
という仕組み使っていて、そのNSURLRequest
はNSURLCache
さらにはNSURLSession
とやらの仕様にしたがってキャッシュを行うらしい。
そしてこのNSURLSession
は指定した上限の、5%までのファイルサイズしかキャッシュしないみたい。
で、React Nativeはどれほど指定しているのかなーと思ったら
_decodedImageCache.totalCostLimit = 5 * 1024 * 1024; // 5MB
なるほど600KBはキャッシュされないですねと。てか上限小さすぎない?そしてそもそも
static const NSUInteger RCTMaxCachableDecodedImageSizeInBytes = 1048576; // 1MB
1MB以上のファイルはRN側でキャッシュしないように指定してるみたい。参照したのはここらへんhttps://github.com/facebook/react-native/blob/v0.38.0/Libraries/Image/RCTImageCache.m#L23
まぁただここらへんの挙動は変数名から推測した程度なので、自信はない。
TL;DR
画像サイズが大きいとダメみたい。250KB以下にした方が良さげ。
Image
コンポーネント、キャッシュしてくれる。シミュレーターでも動作が怪しいかもしれない。実機で動かしたらちゃんとキャッシュしてくれてた。
その他
[追記: 2017/3/30]
書き忘れていたけれど、画像をuriで指定して得るレスポンスのメタデータにcache-contolを含めていないとキャッシュしてくれない。 S3とかに上げるときは設定を確かめるのを忘れずに。
[追記: 2017/4/19]
Facebook内部ではオープンになってるコンポーネントとは別のImage, Cachingモジュールを使ってるみたい。 このIssueが閉じるまでは、Imageコンポーネントのキャッシュは安定しなさそう。自分の場合、3回ぐらいアプリ開くとキャッシュが消されるという挙動をしている。(0.43.3)
https://github.com/facebook/react-native/issues/9581#issuecomment-287834859
参考リンク
[0.32] Image caching broken · Issue #9581 · facebook/react-native · GitHub
https://github.com/facebook/react-native/blob/v0.38.0/Libraries/Image/RCTImageCache.m
ios - How to cache using NSURLSession and NSURLCache. Not working - Stack Overflow