Let me start with the working code that I'm trying to refactor. I'm trying to abstract button creation, and whatever I try, I keep getting the "hooks can only be called inside of the body of a functional component" error.
Following along with a tutorial, I've setup a navigation bar and a button that will take me from the home screen to a "Details" screen. Here's what works:
const DetailsButton = (): JSX.Element => {
const navigation = useNavigation();
return (
<Button title="Details" onPress={() => navigation.navigate('Details')} />
);
};
// And then later on...
<Stack.Screen name="Home"
component={HomeScreen}
options={{ title: 'Master', headerRight: DetailsButton }} />
That button will take me to the Details screen with no issue. But then I got to thinking that I could refactor this into a kind of button factory function:
interface BarButtonProps {
title: string,
destination: string,
};
const BarButton = (buttonProps: BarButtonProps): () => JSX.Element => {
const navigation = useNavigation();
return (): JSX.Element => (
<Button title={buttonProps.title} onPress={() => navigation.navigate(buttonProps.destination)} />
);
}
const DetailsButton = BarButton({title: 'Details', destination: 'Details'});
My plan was to use the DetailsButton component as before. However, when I try to run the code, I get the hooks error. I thought I understood why, and so I tried the following variation:
const BarButton = (buttonProps: BarButtonProps): () => JSX.Element => {
return (): JSX.Element => (
<Button title={buttonProps.title} onPress={() => useNavigation().navigate(buttonProps.destination)} />
);
}
In my mind, the hook now seemed to be within the functional component. But that only got me as far as the home screen. When I press the button I get the same hooks error again. I must be missing some subtle point.
Is it possible to create a higher-order function like this, one that uses a hook, or am I trying something impossible? If it's possible, can someone show me what would work? Thanks.