Evanss
Evanss

Reputation: 23593

React Native's useNavigation hook inside of a custom hook?

Im using React Navigation's useNavigation hook:

In MyComponent.js:

import { useNavigation } from "@react-navigation/native";

const MyComponent = () => {
    const navigation = useNavigation();
    const handleNav = () => {
        navigation.navigate("about");
    };
    return(
        <TouchableOpacity onPress={handleNav}>
            <Text>About</Text>
        </TouchableOpacity>
    )
}

Is there a way to move this functionality to a custom hook? I tried the following:

In useCustomNav.js:

import { useNavigation } from "@react-navigation/native";

const useCustomNav = ({ to }) => {
  const navigation = useNavigation();
  navigation.navigate(to);
  return null;
};

export default useCustomNav;

In MyComponent.js:

import useCustomNav from './useCustomNav';

const MyComponent = () => {
    const handleNav = () => {
        useCustomNav("about");
    };
    return(
        <TouchableOpacity onPress={handleNav}>
            <Text>About</Text>
        </TouchableOpacity>
    )
}

Im getting an error:

Invariant Violation: Invalid hook call. Hooks can only be called inside of the body of a function component.

I understand that this is happening as useNavigation is 'hidden' within a function call but not how to fix it.

The reason Im trying to do this is I'm sharing code between a React Native and React Native Web project but I need to do routing differently. Expo can target different platforms with different file names eg useCustomNav.native.js for native and useCustomNav.web.js for the web. So I need to have a swappable function for routing for the different platforms. I cant have the useNavigation hook in MyComponent as it's only going to be used for native, it will error for web.

Upvotes: 4

Views: 5992

Answers (1)

Ravi
Ravi

Reputation: 141

You can return a function from the custom navigator hook to let you navigate to the route that you want.

const useCustomNav = () => {
  const navigation = useNavigation();

  const goTo = to => navigation.navigate(to);

  return {goTo};
};

And use it like:

const MyComponent = () => {
    const navigator = useCustomNav();

    const handleNav = () => {
        navigator.goTo("about");
    };

    return(
        <TouchableOpacity onPress={handleNav}>
            <Text>About</Text>
        </TouchableOpacity>
    )
}

Upvotes: 7

Related Questions