📔

react-native-pager-viewのパフォーマンス改善

に公開

react-native-pager-viewとは?

この記事に辿り着いたということはすでにご存知かもしれませんが、一応紹介します。react-native-pager-viewとはスワイプでページを簡単に切り替えられるようにするライブラリです。商品紹介などでアイテムごとに横にスライドさせたい時など便利です。

↓に動画サンプルがあるのでどんな動きか気になる方は見てみてください。

https://github.com/callstack/react-native-pager-view

またExpoの公式サイトでも紹介されています。
https://docs.expo.dev/versions/latest/sdk/view-pager/

改善前

改善前は以下のように書いてました。

import PagerView from "react-native-pager-view";
...

export default function Page() {
    const ref = useRef<PagerView>(null);
    ...
    return (
        <View style={styles.container}>
            ...
            <PagerView
                ref={ref}
                style={styles.container}
            >
                {items.map((item) => (
                    <Component key={item.name} item={item} />
                )}
            </PagerView>
            ...
        </View>
    )
}

PagerViewコンポーネントの中でitemsという配列を回し、Componentを描画という形ですね。

最初はこれでよかったんですが、itemsの数が増えてくるとこの画面を表示を表示するのにかなり時間がかかるようになってしまっていました。

また何個目のitemが表示されているか分かるように 3/100 みたいな感じで表示していたのですが、これも早くスワイプすると数字が反映されるまで遅いといった不具合がありました。

改善後

以下のように改善しました。

export default function Page() {
    const ref = useRef<PagerView>(null);
    const [loadedPages, setLoadedPages] =
        useState<{ [key: number]: boolean}> ({ 0: true });
    ...
    return (
        <View style={styles.container}>
            ...
            <PagerView
                ref={ref}
                style={styles.container}
                onPageSelected={(e) => {
                    const pageIndex = e.nativeEvent.position;
                    setLoadedPages((prev) => ({
                    ...prev,
                    [pageIndex]: true,
                    [pageIndex - 1]: true,
                    [pageIndex + 1]: true,
                }));
        }}
            >
                {items.map((item) =>
                    loadedPages[i] ? (
                        <Component key={item.name} item={item} />
                    ) : (
                        <View key={item.name} />
                    )
                }
            </PagerView>
            ...
        </View>
    )
}

loadedPagesというstateを作成し、今表示しているページとその付近のページだけComponentを表示し、あとは中身のないViewコンポーネントだけを表示するように修正しました。

こうすると最初に大量にComponentを描画する必要がなくなるので、初期描画も速くなり、スワイプ関連でのバグも無くなりました。

注意点としてはViewコンポーネントのkeyにComponentで指定しているkeyと同じ値を指定しないと表示されなくなります。

Discussion