React NativeでFlatList/SectionListを使うときに実施したい性能改善策
おことわり
この記事は以下の記事に載っていた内容を拾ってきただけです。
備忘録と英語読みたくない人に向けて。
FlatList/SectionListはrenderItemがしょっちゅう走る
React Nativeでリスト形式の実装をしようと思うと、FlatListかSectionListを使用します。
(くれぐれもListViewは使用しないように!)
こんなレイアウトですね。
で、大体はリストを表示するだけじゃなくて、表示されたリストから何かを選択して次の画面、みたいに使用すると思います。
このときに、リストの1つをタップしただけで全リストの再レンダリングが走ります。
リストの件数が少ないうちは良いですが、多くなってきたらとてもじゃないけど辛くなるでしょう。
レンダリング制御ならReact.memo/useMemo
自分は最近存在を知ったのですが、React.memo/useMemoというやつでレンダリング制御ができるんですね。
これを使って毎回レンダリング走らないようにしましょう。
適用方法は簡単、FlatList/SectionListをまるっとuseMemoで包んで置き換えるだけです。
export default function HomeScreen() {
const renderItem = ({ item, index }) => {
return (
<TouchableHighlight onPress={() => {
console.log('test')
}}>
<Text>{item.text}
</Text>
</TouchableHighlight>
)
}
return (
<View style={{ flex: 1, }}>
<FlatList
keyExtractor={item => item.id}
data={data}
renderItem={renderItem}
/>
</View>
)
}
こんな感じで書いていたものを、以下のように書き換えます。
(書き方がちょっとイケテナイ感じはありますが、その辺は好みで書き換えてください)
export default function HomeScreen() {
const renderItem = ({ item, index }) => {
return (
<TouchableHighlight onPress={() => {
console.log('test')
}}>
<Text>{item.text}
</Text>
</TouchableHighlight>
)
}
const FlatListRender = useMemo(() => {
return (<FlatList
keyExtractor={item => item.id}
data={data}
renderItem={renderItem}
/>
)
}, [data])
return (
<View style={{ flex: 1, }}>
{FlatListRender}
</View>
)
}
これで、Itemをタップしてもレンダリングが走らないようになります。
useMemoの第二引数のリストが再レンダリング対象になるので、リストのデータ以外に対象がある場合はこちらも含めるようにします。
あとはrenderItemの中も場合によってはmemo化したりしてもっと改善できそうな気がします。
まぁ、その辺はアプリの扱うデータによって適宜調整でしょうか。
とりあえず、FlatList/SectionListを使用する場合はやっておいて損はない改善かなと思います。
関係ないけど、画像ファイルドラッグ&ドロップで貼り付けられました。
超便利。
宣伝
例で上げた画像は「ツイメモ」という自作スマホアプリです。
ツイートの下書き管理に特化したメモ帳、という位置付けで、ツイート後の反響なども見れるアプリです。
どんなツイートがバズったか、とかを分析してガッツリやりたいツイ廃の方はぜひ。
iOS版はリリース済み、Android版はリリース準備中です。
Discussion