taiki-t's diary

React Native, Rails そして雑多な記録: The world is waiting for you to give it a meaning.

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という仕組み使っていて、そのNSURLRequestNSURLCacheさらには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

Change RCTImageLoader's Cache System to default NSURLRequest's cache … · facebook/react-native@631785f · GitHub

https://github.com/facebook/react-native/blob/v0.38.0/Libraries/Image/RCTImageCache.m

URLSession:dataTask:willCacheResponse:completionHandler: - NSURLSessionDataDelegate | Apple Developer Documentation

ios - How to cache using NSURLSession and NSURLCache. Not working - Stack Overflow