背景
React Native で、スタックナビゲーションを使わずReactの要素として自前のモーダルを利用する機会がありました。
フレームワークの作法から外れて自前でナビゲーションをやるときに問題になるのは、OSが提供する機能との相互運用性です。今回の場合では、モーダルが開いているときにAndroidの戻るボタンが押されたら、前に表示していたスクリーンに戻るのではなく同一のスクリーンのままでモーダルを閉じるような動作を実現したくなります。
この記事では、React Native の BackHandler を用いて「戻る」機能の動作を制御し、モーダル等の開閉状態と繋ぎこんだ動作を実現するコードスニペットを紹介します。
環境
- React Native 0.73
- Expo SDK 50
- Expo Router 3.4
直接関係があるのは React Native のバージョンのみです。
方針
React Native の機能である BackHandler を利用すると、OSで用意されている「戻る」機能の動作を制御することができます。
コード例
expo-routerが提供している useFocusEffect
を利用しています。 react-navigation を使っている場合でも同じコードが動作するはずです。
// backhandler をインポート import { BackHandler } from "react-native"; import { useFocusEffect } from 'expo-router'; import { useCallback, useState } from 'react';
// モーダルの開閉を表すステート const [isModalOpen, setIsModalOpen] = useState(false); useFocusEffect(useCallback(() => { const closeModal = () => { setIsModalOpen(false); return true; }; // モーダルが開いているときはBackHandlerにイベントリスナを追加、モーダルが閉じている場合はnullを返す const handler = isModalOpen ? BackHandler.addEventListener('hardwareBackPress', closeModal) : null; // イベントリスナを追加したときだけクリーンアップ時に削除する return () => handler?.remove(); }, [isPreviewModalOpen]));