How to use useNavigation() within @react-navigation drawer?
Asked Answered
F

4

8

Current Behavior

I have a react-native application that use react-navigation v5 for the routing.

  1. I have a drawer (offeset menu left) in all my views
  2. I use the stackNavigation for page transition.

Because of (1), my structure is drawerNavigator (a) > stackNavigator (b) > views (c).

When I try to call the useNavigation() hook within my <DrawerContent />, I have the following error:

Error: We couldn't find a navigation object. Is your component inside a navigator?
    at useNavigation (bundle.js:8766)

Yes, I am not inside the stackNavigator so the hook cannot be called

Expected Behavior

I expect to have navigation available within my <DrawerContent />.

Your Environment

| software                       | version |
| ------------------------------ | ------- |
| iOS or Android                 | iOS, Android and web
| @react-navigation/native       | 5.0.0-alpha.41
| @react-navigation/stack         | 5.0.0-alpha.63
| @react-navigation/drawer       | 5.0.0-alpha.41
| react-native-reanimated        | 1.4.0
| react-native-gesture-handler   | 1.5.3
| react-native-safe-area-context | 0.6.2
| react-native-screens           | 2.0.0-alpha.32
| react-native                   | https://github.com/expo/react-native/archive/sdk-36.0.0.tar.gz
| expo                           | SDK36
| node                           | v13.5.0
| npm or yarn                    | 6.13.7

How can I use @react-navigation/stack inside @react-navigation/drawer or how should I build my drawer and app with them?

Fessler answered 6/2, 2020 at 4:35 Comment(0)
F
14

This is possible using https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html

Create RootNavigation :

import { createRef } from 'react';

export const navigationRef = createRef();

export function navigate(name, params) {
  navigationRef.current?.navigate(name, params);
}

export function goBack() {
  navigationRef.current?.goBack();
}

In App.js:

import { navigationRef } from './navigation/RootNavigation';
// ...
<NavigationContainer
  ref={navigationRef}
>
  {children}
</NavigationContainer>

Then import RootNavigation from any source and you will not have to worry about the react tree.

Fessler answered 6/2, 2020 at 12:10 Comment(2)
Anyway, can't reach closeDrawer function. For me, this example is working: rb.gy/ra0irsFulton
This also brings a lot of problems (missing function, bad current route, etc...), be aware that I have not found a good and valid solution that restore all the features.Fessler
J
2

I'm also using React Navigation 5x, I followed this guide and still succeed using first approach (for old RNavigation). Details: mock the useNavigation function

jest.mock(‘react-navigation-hooks’, () => ({
 useNavigation: () => jest.fn(),
 useNavigationParam: jest.fn(jest.requireActual(
  'react-navigation-hooks'
 ).useNavigationParam),
}));
Jempty answered 3/9, 2020 at 6:11 Comment(1)
How will i implement this function in my testing component. Can you give me an example with V5?.Professorship
A
1

You don't have to use useNavigation if you're on a screen in the Navigator.

The structure of the navigator is as follows.

  • stackNavigator
    • drawerNavigator
      • drawerScreens
  • stackScreens

The screen movement is as follows.

Example

function HomeScreen({ navigation }) {
  return (
    <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
      <Button
        onPress={() => navigation.navigate('moveScreenName')}
        title="Go to moveScreenName"
      />
    </View>
  );
}

useNavigation is a hook which gives access to navigation object. It's useful when you cannot pass the navigation prop into the component directly, or don't want to pass it in case of a deeply nested child.

useNavigation() returns the navigation prop of the screen it's inside.

Example

function MyBackButton() {
  const navigation = useNavigation();

  return (
    <Button
      title="Back"
      onPress={() => {
        navigation.goBack();
      }}
    />
  );
}
Analemma answered 6/2, 2020 at 4:50 Comment(4)
I am not on a screen in the navigator, I am within the DrawerContent. Also, my structure is drawerNavigator wrapping stackNavigator, do you suggest to do the opposit? If I did that, it's only because I want one drawer for all my app and not one per stack viewsFessler
@DimitriKopriwa What you're trying to do now is put all the stacks in one drawer. The same is the way I do it. The structure is at one's disposal. But to do the way you want, my answer is well structured.Analemma
I have tried to use the layout you recommended but unfortunately, I have this error: A navigator can only contain 'Screen' components as its direct children (found DrawerNavigator). Do you have an example of implementation if you have tried to make one?Fessler
Except your file structure which tell that stackScreens brother of stackNavigator which is literally impossible, the rest is not related to my question. I am curious to see a working example of how you would create the drawer in a different scenario than mine without creating multiple drawers for each pages.Fessler
W
0

You can follow this video in here - https://youtu.be/hLP1G29bbLU

You can see the usage of useNavigation hook in the video.

Wanyen answered 31/8, 2020 at 6:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.