Skip to content
Advertisement

undefined is not an object (evaluating ‘navigation.navigate’) when trying to navigate to a file that will open camera on the phone

I’m trying to navigate to my page “CameraPage.js” but I’m getting this error “undefined is not an object (evaluating ‘navigation.navigate’)”. Can anybody see the problem? This ismy first question here so please tell me if I can be more specific.

Here’s my App.js:

import { StyleSheet, Text, View, TouchableOpacity, Pressable } from 'react-native';
import React, {useEffect, useState} from "react";
import { FontAwesome } from '@expo/vector-icons';
import { useNavigation } from '@react-navigation/native';


export default function App({ navigation }) {

    return (
        <View style={styles.container}>
            <View style={styles.buttonContainer}>
                <TouchableOpacity onPress ={() => navigation.navigate('CameraFunction')}>
            <FontAwesome name="camera" size={100} color="#FFB6C1" />
                </TouchableOpacity>
                <Pressable>
            <FontAwesome name="photo" size={100} color="#FFB6C1" />
                </Pressable>
            </View>
        </View>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#FFDBE9'
    },
    buttonContainer: {
        backgroundColor: 'transparent',
        justifyContent: 'space-between',
    },
});
Here is my CameraPage.js file:

import {StyleSheet, Text, View, TouchableOpacity} from 'react-native';
import {Camera, CameraType} from 'expo-camera';
import {useEffect, useState} from "react";


export default function CameraPage() {
    const [hasPermission, setHasPermission] = useState(null);
    const [type, setType] = useState(CameraType.back);

    useEffect(() => {
        (async () => {
            const {status} = await Camera.requestCameraPermissionsAsync();
            setHasPermission(status === 'granted');
        })();
    }, []);

    if (hasPermission === null) {
        return <View/>;
    }
    if (hasPermission === false) {
        return <Text>No access to camera</Text>;
    }
    return (
        <View style={styles.container}>
            <Camera style={styles.camera} type={type}>
                <View style={styles.buttonContainer}>
                    <TouchableOpacity
                        style={styles.button}
                        onPress={() => {
                            setType(type === CameraType.back ? CameraType.front : CameraType.back);
                        }}>
                        <Text style={styles.text}> Flip </Text>
                    </TouchableOpacity>
                </View>
            </Camera>
        </View>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    camera: {
        flex: 1,
    },
    buttonContainer: {
        flex: 1,
        backgroundColor: 'transparent',
        flexDirection: 'row',
        margin: 20,
    },
    button: {
        flex: 0.1,
        alignSelf: 'flex-end',
        alignItems: 'center',
    },
    text: {
        fontSize: 18,
        color: 'white',
    },
});
Here is my navigation file:

import React from 'react';
import {createStackNavigator} from '@react-navigation/stack';
import {NavigationContainer} from '@react-navigation/native';
import CameraPage from "../Camera/CameraPage";

const Routes = createStackNavigator();

export default function Navigator() {
    return (
        <NavigationContainer>
            <Routes.Navigator>
                <Routes.Screen
                    name="CameraFunction"
                    component={CameraPage}
                    />
            </Routes.Navigator>
        </NavigationContainer>
    );
}

Advertisement

Answer

Your navigation container must be wrapped around the root of your application or otherwise the navigation object will not be passed to the components that you have defined as screens.

The following fixes your issue.

export default const App = () => {
    return (
        <NavigationContainer>
            <Routes.Navigator>
                <Routes.Screen name="Home" component={HomeScreen} />
                <Routes.Screen
                    name="CameraFunction"
                    component={CameraPage}
                    />
            </Routes.Navigator>
        </NavigationContainer>
    );
}

Your HomeScreen contains the old code from App, but now you can access the navigation object since we have defined HomeScreen as a screen inside the navigator. It will be passed to that screen by the navigation framework. Notice as well that HomeScreen is the initial screen of your application.

export default function HomeScreen({ navigation }) {

    return (
        <View style={styles.container}>
            <View style={styles.buttonContainer}>
                <TouchableOpacity onPress ={() => navigation.navigate('CameraFunction')}>
            <FontAwesome name="camera" size={100} color="#FFB6C1" />
                </TouchableOpacity>
                <Pressable>
            <FontAwesome name="photo" size={100} color="#FFB6C1" />
                </Pressable>
            </View>
        </View>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#FFDBE9'
    },
    buttonContainer: {
        backgroundColor: 'transparent',
        justifyContent: 'space-between',
    },
});

Notice, that you need to navigate back to the HomeScreen once you have navigated to the CameraPage. You can use the navigation object in the CameraPage as well and trigger navigation.goBack to achieve this effect.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement