2020/5/29 React Native Meetup #10 LT
List型View FlatList とのパフォーマンスとの戦い@potproList型View FlatList とのパフォーマンスとの戦い 1
View Slide
⾃⼰紹介@potpro ぽとぷろhttps://blog.potproject.net/https://mastodon.potproject.net/PHP / Go / JS Vue / React仕事で⼤体サーバサイドエンジニア趣味でフロントエンド/インフラエンジニアList型View FlatList とのパフォーマンスとの戦い 2
趣味でMastodonのクライアントアプリを作ってますpotproject/ikuradonExpo Managed Workflow Eject無し での開発今時っぽいUI最近React Navigation v5 + ReactHooks にすべて書き換えている※画⾯は開発中のものですList型View FlatList とのパフォーマンスとの戦い 3
今⽇の題材この部分のパフォーマンスの話FlatList を使⽤していますこれの話が今回はメインです投稿は気にしないで下さいList型View FlatList とのパフォーマンスとの戦い 4
FlatListReact NativeにおけるList型Viewの標準インターフェースヘッダーやフッター、リフレッシュコントロール 引っ張ったら更新されるアレ などが標準搭載ListViewというものも存在したが、既にDeprecatedになりこちらが現在は標準List型View FlatList とのパフォーマンスとの戦い 5
実装例 全く知らない⼈のためにconst DATA = [{id: '1',title: 'First Item',},{id: '2',title: 'Second Item',},{id: '3',title: 'Third Item',},];export default function App() {return (data={DATA}renderItem={({ item }) => {item.title}}keyExtractor={item => item.id}/>);}List型View FlatList とのパフォーマンスとの戦い 6
パフォーマンス問題にぶち当たるList型View FlatList とのパフォーマンスとの戦い 7
FlatListのパフォーマンス問題実際にアプリを開発時に浮上した問題リスト更新時、 リストに追加がなくても 必ず1秒以上かかってしまう普段使いしてるとちょっと気になるレベルネットワークが遅いのかなと思ったけどレスポンスは50ms以下・・・更新しまくるとハイスペックなはずのiPhone11 Proの発熱がマッハUIのFPSもかなり落ちてしまうList型View FlatList とのパフォーマンスとの戦い 8
FlatListのパフォーマンス問題リストの数が増えるとパフォーマンスがかなり悪化することは、割と知られているいろんなところで話された結果、最適化の⽅法についてgithubリポジトリが存在するhttps://github.com/filipemerker/flatlist-performance-tipsここを参考に改善していくList型View FlatList とのパフォーマンスとの戦い 9
FlatListのチューニング概要⼤体⼤きく分けて2つの⽅法がありますpropsのチューニングFlatListに渡す値を調整することでパフォーマンス改善につながることがある今回のケースではメリットが薄く、デメリットが多かった うまく表⽰されない、スクロールが重くなってしまうなどリストの構造を変えるリスト⾃体のコンポーネントを軽くする戦略デメリットもある場合もあるが、場合によってはWin-Winの物もあるこちらを主にやっていくことで、パフォーマンスに⼤きな効果があったList型View FlatList とのパフォーマンスとの戦い 10
実際に改善したこと・⼿法効果が⾼かったものを紹介最終的に割と⼀般的なReactのパフォーマンス向上⽅法になったので、FlatList以外にも使える⽅法だと思いますList型View FlatList とのパフォーマンスとの戦い 11
改善 1 Viewの数を減らすViewの数を減らし、シンプルにする1つ増えるとリストの数だけ増える為、レンダリングコストが上がる計算量:O n になり塵も積もれば⼭となる存在に↑こういった Viewの無駄遣いを辞めるこんなことしなくてもstyleをうまく使えば⼤体やりたいことは実現できるはずList型View FlatList とのパフォーマンスとの戦い 12
改善 2 List内部でReact ReduxのStoreを使わないRowの中で useSelectorクラスなら connectを使わないコストが⾼い為、FlatListの外でuseSelectorをして、Propsで渡すこれも計算量0 n の問題export default function App() {// Redux Store取得const data = useSelector(reducer);return (data={data}renderItem={({ item }) => {item.title}}keyExtractor={item => item.id}/>);}List型View FlatList とのパフォーマンスとの戦い 13
改善 3 React.memo useMemo を使うどちらもデータを保持しておき、データを⽐較してレンダリングしないできるパフォーマンス改善⽤機能React.memoはコンポーネント全体、 useMemoは⼀部に使⽤可能この2つはfunctional component⽤なので、クラスは PureComponentを使う更新されない場合はレンダリングされないので、パフォーマンスが⼤幅に向上しかし要件にうまく合っていないと不具合となってしまうので注意今の時間を表⽰する、みたいなものはうまく動作しなくなる可能性ありList型View FlatList とのパフォーマンスとの戦い 14
React.memo 使⽤例export default function App() {// Redux Store取得const data = useSelector(reducer);//Propsで受け渡すreturn (data={data}extraData={data}renderItem={({ item }) => }keyExtractor={item => item.id}/>);}function List({id, title}){return ({title});}// React.memo()の引数にReactコンポーネントを渡す//旧Propsと新Propsを⽐較して判断します// IDとタイトルが変更された時だけレンダリングconst Row = React.memo(List, (p, n) => p.id === n.id && p.title === n.title);List型View FlatList とのパフォーマンスとの戦い 15
改善後Before: リスト更新時の処理: 1200 更新0件 〜2000 更新40件 msAfter: リスト更新時の処理: 50 更新0件 〜 1200 更新40件 msチューニングと不要不急のレンダリングをやめたことで、かなり快適になった発熱もなくなりましたList型View FlatList とのパフォーマンスとの戦い 16
まとめFlatListは使いやすいけど、パフォーマンス問題は結構⼤変100以上のリストをリッチに扱うと厳しくなる⾊々やっても実は問題がまだまだあるメモリ使⽤量はやっぱり⾼い、マシになったが爆速とは⾔えない更に解決するためにFlatList以外を使う⽅法もあるネイティブ実装で早いらしい bolan9999/react-native-largelist幅を計算する必要があるがパフォーマンスが⾼いらしい Flipkart/recyclerlistviewまだ検証できていないので時間があるときに検討したいList型View FlatList とのパフォーマンスとの戦い 17
ご静聴ありがとうございましたList型View FlatList とのパフォーマンスとの戦い 18