Home > Back-end >  React Native, how to import navigation container?
React Native, how to import navigation container?

Time:06-06

My idea is to have nav.js contain the navigation container for my mobile application, along with all of the screens here (i.e. the homescreen). This file would theoretically let me include buttons in another file that would let me navigate to the screen in the nav.js file that I specified with the button.

I made a constant for this called NavBar and exported it, but when I tried to import into my photo.js file (an example file where I want to include a button that lets me navigate to my 'Tasks' screen), I got the error:

Error: Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitly. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them.

I tried simply making my own button in photo.js instead of : <Button title="Go to tasks" color="lightblue" onPress={() => navigation.navigate('Tasks')}/>, but that only gave me the error that the variable navigation could not be found.

nav.js

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { StyleSheet, View, Button, ScrollView } from 'react-native';
import TaskApp from './taskapp';
import AddTank from './tank';

const NavBar = () => {

    const Stack = createNativeStackNavigator();

    {/* Homescreen */}
    const HomeScreen = ( {navigation} ) => {
        return (
        <ScrollView style={homeStyle.container}>
            <AddTank />
            <Button title="Go to tasks" color="lightblue" onPress={() => navigation.navigate('Tasks')}/>
        </ScrollView>
        )
    }

    {/* Default config */}
    const Config = ( {navigation } ) => {
        return (
        <View></View>
        )
    }

    return (

    <NavigationContainer>
        <Stack.Navigator initialRouteName='Home'>
        <Stack.Screen name="Home" component={HomeScreen}/>
        <Stack.Screen name="Tasks" component={TaskApp}/>
        <Stack.Screen name="Config" component={Config}/>
        </Stack.Navigator>
    </NavigationContainer> 

    )

}

const homeStyle = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: '#E8EAED',
    },
    tasks: {
      flex: 1,
      height: 30,
      width: 30,
      backgroundColor: '#E8EAED',
    },
  });

export default NavBar;

photo.js

import React, {useState, useEffect} from 'react';
import { StyleSheet, Text, View, Button, Image, ImageBackground } from 'react-native';
import { NavigationContainer, StackActions } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import * as ImagePicker from 'expo-image-picker';
import NavBar from './nav';


const AddPhoto = () => {
const add = {uri: 'https://media.discordapp.net/attachments/639282516997701652/976293252082839582/plus.png?width=461&height=461'}
const Stack = createNativeStackNavigator();
const [hasGalleryPermission, setHasGalleryPermission] = useState(null);
  const[ image, setImage ] = useState(null);
  useEffect(() => {
    (async () => {
      const galleryStatus = await ImagePicker.requestCameraMediaLibraryPermissionAsync();
      setHasGalleryPermission(galleryStatus.status === 'granted');
    })();
  }, []);

  const pickImage = async () => {
    let result = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.Images,
      allowsEditing: true,
      aspect: [4,3],
      quality:1,
    });

    console.log(result);

    if (!result.cancelled){
      setImage(result.uri);
    }
  };

  if (hasGalleryPermission === false){
    return <Text>No access to internal storage.</Text>
  }


    return (
        <View style={styles.container}>
            {image && <ImageBackground source={{uri: image}} style={styles.tankPhoto}/>}

            <Button title="Add photo" color="lightgreen" onPress={() => pickImage()} />

            <NavBar />

        </View>
    )


}

const styles = StyleSheet.create({
    container: {
        borderColor: '#C0C0C0',
        borderWidth: 1,
        backgroundColor: '#FFF',
        borderRadius: 50,
        width: 330,
        flex: 1,
        alignItems: 'center',
        marginLeft: 'auto',
        marginRight: 'auto',
        margin: 30,
    },
    tankPhoto: {
      flex: 1,
      height: 150,
      width: 200,
      borderWidth: 1, 
      margin: 25,
    },
})

export default AddPhoto;

What am I doing wrong, or is there a better way to do this? What I need:

let me include buttons in another file that would let me navigate to the screen in the nav.js file that I specified with the button.

React native navigation documentation: https://reactnavigation.org/docs/getting-started

CodePudding user response:

Move these lines outside the NavBar component:

 const Stack = createNativeStackNavigator();

    {/* Homescreen */}
    const HomeScreen = ( {navigation} ) => {
        return (
        <ScrollView style={homeStyle.container}>
            <AddTank />
            <Button title="Go to tasks" color="lightblue" onPress={() => navigation.navigate('Tasks')}/>
        </ScrollView>
        )
    }

    {/* Default config */}
    const Config = ( {navigation } ) => {
        return (
        <View></View>
        )
    }

CodePudding user response:

I ended up making this work. I defined const navigation = useNavigation(); in my code (under AddPhoto constant) and imported: import { useNavigation } from '@react-navigation/native'; in the same file (photo.js).

  • Related