react-nativenavigation-drawerreact-propsreact-navigation-stack

React-Native, Navigation, Drawers and passing inline functions with props


I have a Drawer Navigator nested inside a Stack navigator. It all works fine but I get the following warning:-

Looks like you're passing an inline function for 'component' prop for the screen 'Home' (e.g. component={() => }). Passing an inline function will cause the component state to be lost on re-render and cause perf issues since it's re-created every render. You can pass the function as children to 'Screen' instead to achieve the desired behaviour.

Here is the code.

const [isAuthenticated, setIsAuthenticated] = React.useState(false);
const [initialRoute, setInitialRoute] = React.useState("");

const handleSignOut = () => {
    // TODO implement sign out mechanism
};

return (
    <NavigationContainer>{
        <Stack.Navigator initialRouteName="Sign In"         >
            {isAuthenticated ? (
                <Stack.Screen name="Home"
                    component={() => <HomeDrawer initialRoute={initialRoute} handleSignOut={handleSignOut}/>}
                    options={({ route, navigation }) => ({
                        headerTitle: getFocusedRouteNameFromRoute(route),
                        headerLeft: () => (
                            <Button
                                title="Menu"
                                onPress={() =>
                                    navigation.dispatch(DrawerActions.toggleDrawer())
                                }
                            />
                        ),
                        headerRight: () => (
                            <Button onPress={handleSignOut} title="Sign Out" />
                        ),
                    })}
                />
            ) : (

            ...

I fixed the warning by moving the component, but now the Drawer has stop working completely and I get this error:-

The action 'TOGGLE_DRAWER' was not handled by any navigator. Is your screen inside a Drawer navigator?

Here is the new code.

const [isAuthenticated, setIsAuthenticated] = React.useState(false);
const [initialRoute, setInitialRoute] = React.useState("");

const handleSignOut = () => {
    // TODO implement sign out mechanism
};

const Draw = () => {<HomeDrawer initialRoute={initialRoute} handleSignOut={handleSignOut}/>};

return (
    <NavigationContainer>{
        <Stack.Navigator initialRouteName="Sign In"         >
            {isAuthenticated ? (
                <Stack.Screen name="Home"
                    component={Draw}
                    options={({ route, navigation }) => ({
                        headerTitle: getFocusedRouteNameFromRoute(route),
                        headerLeft: () => (
                            <Button
                                title="Menu"
                                onPress={() =>
                                    navigation.dispatch(DrawerActions.toggleDrawer())
                                }
                            />
                        ),
                        headerRight: () => (
                            <Button onPress={handleSignOut} title="Sign Out" />
                        ),
                    })}
                />
            ) : (

            ...

I'm new to React-Native and on a steep learning curve. I've read a bunch of tutorials but stumped on this one. I can see I need to pass initialRoute at least, but not sure how to do that. A fix with an explanation would be great.


Solution

  • I found the answer in the end. It was pretty straight forward, but not when there are so many things to learn at once :-) When I moved the component like so it all worked.

    <Stack.Screen name="Home"
        options={({ route, navigation }) => ({
            headerTitle: getFocusedRouteNameFromRoute(route),
            headerLeft: () => (
                <Button
                    title="Menu"
                    onPress={() =>
                        navigation.dispatch(DrawerActions.toggleDrawer())
                    }
                />
            ),
            headerRight: () => (
                <Button onPress={handleSignOut} title="Sign Out" />
            ),
        })}
    >
        {(props) => (
            <HomeDrawer {...props} initialRoute={initialRoute} handleSignOut={handleSignOut} />
        )}
    </Stack.Screen>
    <Stack.Screen name="TEST" component={TestScreen}
        screenOptions={{ headerShown: true }}
        options={{ headerTitle: "Hello" }}
    />