Use react navigation.navigate inside a normal function - (no hooks allowed i.e. useNavigation)?

Viewed 4710

I'm trying to put a function that navigates to a screen in an other module and export it, but navigation does not work. I tried with UseNavigation() but I get an error, namely: Unhandled promise rejection: Invariant Violation: Hooks can only be called inside the body of a function component.

Is there a way to use navigation in a normal function, or anything else.

import React, { useState, useEffect, useCallback } from "react";
import { AsyncStorage, Alert } from "react-native";
import { useNavigation } from "react-navigation-hooks";

export const startMixGame = async (categoryIsChosen, withTimer) => {
  const navigation = useNavigation();

  if (categoryIsChosen) {
    if (withTimer) {
      await AsyncStorage.setItem("useTimer", "true");
      navigation.navigate({
        routeName: "MixedQuestions",
        params: {
          categoryId: "1"
        }
      });
    } else if (!withTimer) {
      // console.log("withTimer", withTimer);

      await AsyncStorage.setItem("useTimer", "false");
      navigation.navigate({
        routeName: "NoTimerMixedQuestions",
        params: {
          categoryId: "1"
        }
      });
    }
  }

};

Thanks

3 Answers

Yes, use a singleton service holding a reference to the navigation, at the root of your app save with a useEffect the reference in the singleton, so you can you it everywhere. Something like this:

class NavigationService {
  constructor() {
    this._navigation = null;
  }

  set navigation(nav) {
    this._navigation = nav;
  }

  get navigation() {
    return this._navigation;
  }
}

const navigationService = new NavigationService();

export default navigationService;

and in your main screen / view

    const HomeScreen = ({navigation}) => {
      useEffect(() => {
        navigationService.navigation = navigation;
      }, [navigation]);
   ....

and now everywhere you can do this

import navigationService from '../services/navigation';

navigationService.navigation.navigate('Screen');

check this https://reactnavigation.org/docs/navigating-without-navigation-prop/

you can save a reference to NavigationContainer and use it to navigate.

App

import AppNavigator from './AppNavigator'
...
render (){
 return (<AppNavigator/>)
}

AppNavigator

import * as React from 'react';
import AppStack from './AppStack';
import {NavigationContainer} from '@react-navigation/native';
import NavigationService from './NavigationService';

const AppNavigator = () => {
    return (
        <NavigationContainer
            ref={NavigationService.instance}
        >
            <AppStack/>
        </NavigationContainer>
    );
};
export default AppNavigator

AppStack

import {createStackNavigator} from '@react-navigation/stack';

const Stack = createStackNavigator();


export default () => {
    return (
        <Stack.Navigator>

             // add all screens here
             <Stack.Screen
                name={'Home'}
                component={HomeCpmponent}
            />

        </Stack.Navigator>
    )
}
import {NavigationContainerRef} from '@react-navigation/native';
import * as React from 'react';
import {boundClass} from 'autobind-decorator';

@boundClass
class NavigationService {
    instance = React.createRef<NavigationContainerRef>();

    dispatch(action) {
        this.instance.current?.dispatch(action)
    }

    getInstance() {
        return this.instance?.current
    }

    canGoBack() {
        return this.getInstance()?.canGoBack()
    }

    navigate(routeName: string, params: any) {
        return this.getInstance()?.navigate(routeName, params)
    }

}

export default new NavigationService()

You can use NavigationService.dispatch() and import {CommonActions, StackActions} from '@react-navigation/native'; or NavigationService.navigate('home',{id:'test1'}) or ...

Actually, now that I see it again, I could just pass the navigation as a argument/parameter, like:

export const startMixGame = async (categoryIsChosen, navigation, withTimer) => { ...}
Related