プロジェクトでReact Navigation 5を使用していますが、特定のポイントの後にユーザーが戻るのをブロックするのに問題があります。
アプリは、次のようなネストされたナビゲーション構造を使用します。
_ROOT (STACK)
|-- LoginScreens (STACK - options={{ gestureEnabled: false }} )
| |-- Login (SCREEN) -> when successful navigate to "Home"
| +-- Register (SCREEN) -> after registration, navigate to "Login"
|
+-- Home (TABS - options={{ gestureEnabled: false }} )
|-- BlahBlah (SCREEN)
|-- MyProfile (SCREEN)
+-- Dashboard (TABS)
|-- AllTasks (SCREEN)
+-- SomethingElse (SCREEN)
_
ユーザーが正常にログインすると、ユーザーはHome
画面に送信され、LoginScreens
画面に戻ることができなくなります。
componentDidMount
のHome
ライフサイクルメソッドとuseFocusEffect
フックを次のように使用しようとしました:
BackHandler
へのコールバックを配置すると、ハンドラーからtrueが返されます(trueは、バックアクションが処理され、それ以上バックハンドラーが呼び出されないことを意味します)。 Home
の画面内のバックナビゲーションをすべてブロックします(たとえば、ダッシュボードからMyProfileに戻ることができません)。navigation.reset({ index: 1, routes: [{ name: "Home" }] })
を使用します。 _index: 1
_がない場合、ナビゲーションはROOTのinitialRoute(この場合はLoginScreens
)に戻ります。 _index: 1
_を使用すると、_Maximum update depth exceeded
_エラーがスローされます。Home
に直接移動する代わりに、navigation.reset()
を使用してみました(注:paramsなし、ナビゲーション履歴全体をクリアします)。その後、Home
画面に移動します。現在のルート(ROOTのinitialRoute、この場合はLoginScreens
)がHome
にナビゲートする前にナビゲーション履歴にプッシュされるため、これは望ましい効果を達成しません。Aaaaand ...私はアイデアを使い果たしました。誰か提案はありますか?
まあ、私は認めざるを得ません。v5の新しいリセットメソッドの構文を見つけるのは簡単ではありませんでした。ReactNavigationドキュメントには、サイト内検索機能が本当に必要です。
とにかく、 reset method を使用でき、私にとっては完全に機能しました。
それは次のようになります:
import { CommonActions } from '@react-navigation/native';
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [
{
name: 'Home',
params: { user: 'jane' },
},
],
})
);
アプリの複数の場所で使用するヘルパー関数を作成しました。
import { CommonActions } from '@react-navigation/native';
export const resetStackAndNavigate = (navigation, path) => {
navigation.dispatch(CommonActions.reset({ index: 0, routes: [{ name: path }] }));
};
私は反応ナビゲーションv5のためにこの方法でそれをしました:
アイテムを押すたびに処理できるように、CustomDrawerContent-Componentを作成しました。
(注:header
およびfooter
プロパティは無視してください。これは私の引き出しの調整にすぎません。)
...
import {
DrawerContentScrollView,
DrawerItem,
} from '@react-navigation/drawer';
...
function CustomDrawerContent(props) {
const {
state: {routes, index},
descriptors,
navigation,
header,
footer,
} = props;
return (
<>
{header}
<DrawerContentScrollView {...props}>
{routes.map((route, i) => {
const focused = i === index;
const {title, drawerLabel, drawerIcon} = descriptors[
route.key
].options;
return (
<DrawerItem
key={route.key}
label={
drawerLabel !== undefined
? drawerLabel
: title !== undefined
? title
: route.name
}
icon={drawerIcon}
focused={focused}
onPress={() => {
navigation.dispatch(
CommonActions.reset({index: i, routes: [{name: route.name}]}),
// NOTICE: Removes the routes.<name>.state of the Stack to discard
// navigation-Position if coming back to it via Drawer-Menu.
// If this Stack-State in seeded later on, you can adjust it here needed
);
}}
/>
);
})}
</DrawerContentScrollView>
{footer}
</>
);
}
function MainDrawer(props) {
const {
screen,
screen: {initialRoute},
navigatorProps,
header,
footer,
hideDrawerItems,
} = props;
return (
<Navigator
initialRouteName={initialRoute}
{...navigatorProps}
drawerContent={(drawerProps) => (
<CustomDrawerContent {...drawerProps} header={header} footer={footer} />
)}>
{createMenuEntries(screen, hideDrawerItems)} // that's only an custom implementation of mine to create <Screen>-Entries. Feel free to replace it with your own
</Navigator>
);
}
export default MainDrawer;
少なくとも魔法はここにあります:
{routes.map((route, i) => {
...
onPress => navigation.dispatch => CommonActions.reset({index: ⇒⇒ i ⇐⇐
各ルートをマッピングする際、現在のインデックスと(ドロワーアイテム自体の)ルート名を使用して、ルート状態をリセットします(タップした場合)。
News ⇒ News Detail"
にいて、ドロワーを開いてNews
をもう一度クリックしても、News-Stack
の最初の画面にパイプされるので、これは私の目的には完全にうまく機能します。