🏇

React NativeでFlatList/SectionListを使うときに実施したい性能改善策

2020/10/04に公開

おことわり

この記事は以下の記事に載っていた内容を拾ってきただけです。
備忘録と英語読みたくない人に向けて。

https://medium.com/swlh/how-to-use-flatlist-with-hooks-in-react-native-and-some-optimization-configs-7bf4d02c59a0

FlatList/SectionListはrenderItemがしょっちゅう走る

React Nativeでリスト形式の実装をしようと思うと、FlatListかSectionListを使用します。
(くれぐれもListViewは使用しないように!)
こんなレイアウトですね。

FlatList/SectionList使用例

で、大体はリストを表示するだけじゃなくて、表示されたリストから何かを選択して次の画面、みたいに使用すると思います。
このときに、リストの1つをタップしただけで全リストの再レンダリングが走ります。
リストの件数が少ないうちは良いですが、多くなってきたらとてもじゃないけど辛くなるでしょう。

レンダリング制御ならReact.memo/useMemo

自分は最近存在を知ったのですが、React.memo/useMemoというやつでレンダリング制御ができるんですね。
これを使って毎回レンダリング走らないようにしましょう。

適用方法は簡単、FlatList/SectionListをまるっとuseMemoで包んで置き換えるだけです。

before.js
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>
    )
}

こんな感じで書いていたものを、以下のように書き換えます。
(書き方がちょっとイケテナイ感じはありますが、その辺は好みで書き換えてください)

after.js
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版はリリース準備中です。

https://apps.apple.com/jp/app/id1516487467

Discussion