Twitter アプリなどでよく見かける、アクティブなタブを再度タップしたら、リストビューの最上部へ移動する......といった挙動を React Native で実装したい!というときのやり方。
タブナビゲーションに React Nativation / Expo Router を使っている場合は、 useScrollToTop フックを使うことで、簡単に実現できます。
まずは導入から、 pnpm を使っている場合は次のコマンドで、React Navigation を明示的に導入する:
$ pnpm add @react-navigation/native
次に、ボトムタブを実装する。おおよそ次のようなコード例になるはず。
// @app/_layout.tsx import { Tabs } from "expo-router"; export default function TabLayout() { return ( <Tabs screenOptions={{ headerShown: false, }} > <Tabs.Screen name="index" /> <Tabs.Screen name="explore" /> <Tabs.Screen name="notifications" /> <Tabs.Screen name="profile" /> </Tabs> ); }
次に、実際に useScrollToTop を使う。 useScrollToTop には特定のインターフェースを満たすオブジェクトを渡す必要があるが、今回は scrollToTop だけを実装したものを渡す。
タブの中身と一緒に実装した例だと、次のような形になるはず。
// @app/explore.tsx import { useScrollToTop } from "@react-navigation/native"; import { FlashList, FlashListRef } from "@shopify/flash-list"; import React, { useMemo, useRef } from "react"; import { View } from "react-native"; export default function ExploreScreen() { const listRef= useRef<FlashListRef<any>>(null); const [items, ] = useState<{ id: string }[]>([]); const scrollerObj = useRef<{ scrollToTop: () => void }>(null); const scroller = useMemo(() => { return { scrollToTop: () => { listRef.current?.scrollToOffset({ offset: 0, animated: true }); // 最上部へスクロール } } }, [activeTab]); scrollerObj.current = scroller; useScrollToTop(scrollerObj); return ( <FlashList ref={listRef} keyExtractor={(w) => w.id} data={items} // 略 /> ); }
これだけで Twitter アプリとかでよく見る「ボトムタブナビゲーションをタップしたら上へスクロールする」ができる。簡単。ということでメモでした。