React Navigation Bottom Tabs Navigator plus Modal Screen - react-native

I have the following code to create a Tab using React Native Navigation v6.x:
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
The HomeScreen has a button which should call a Modal Screen.
My question is: How would I add this modal screen in my Navigator to call it from HomeScreen and how would be this call code?
Thanks!

You don't need to include the modal in the navigator to open it from the homepage.
You could do something like this:
const HomeScreen = () => {
const [modalVisible, setModalVisible] = useState(false);
function _myModal() {
return(
<Modal
animationType="slide"
visible={modalVisible}
onRequestClose={() => {setModalVisible(false)}}
>
<Text>Hello, I am a modal!</Text>
</Modal>
)
}
// your code
return (
<View>
{/*your code*/}
<Pressable
onPress={() => setModalVisible(true)}
>
<Text>Show Modal</Text>
</Pressable>
{_myModal()}
</View>
);
};
The React-Native documentation has an example for class component as well in case you're working with these, and more info that should help you as well.

If you want to open modal screen from your home page then you should create a home screen stack navigator and add two screen in that stack(home and modal screens), and then navigate to that modal by pressing button.
Tab Navigator(RootNavigation MyTabs)
...
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStack} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
Stack Navigator(HomeStack)
cosnt Stack = createStackNavigator();
function HomeStack() {
return (
<Stack.Navigator>
<Stack.Screen name="HomeScreen" component={HomeScreen} />
<Stack.Screen name="ModalScreen" component={ModalScreen}
options={{ presentation: 'modal' }} />
</Stack.Navigator>
);
}
HomeScreen
export default function HomeScreen({navigation}) {
return (
<View>
<TouchableOpacity onPress={() => navigation.navigate('ModalScreen'}>
<Text>Open ModalScreen</Text>
</TouchableOpacity>
</View>
)
}

Related

navigation.goBack not working in react native

This is the structure of my project: Tab navigator has two screens DailyTab and WeeklyTab. DailyTab is itself a stack navigator which has two screens Daily and Todos. Daily is the default screen and I am able to navigate from Daily to Todos but the same Todos screen appears when I press the back button on Todos(I expect it to take me to Daily screen)
Main:
const Main = () => {
const Tab = createBottomTabNavigator();
return (
<NavigationContainer independent={true}>
<Tab.Navigator>
<Tab.Screen
name="DailyTab"
component={DailyTab}
/>
<Tab.Screen
name="WeeklyTab"
component={WeeklyTab}
/>
</Tab.Navigator>
</NavigationContainer>
);
};
DailyTab:
const DailyTab = () => {
return (
<NavigationContainer independent={true}>
<Stack.Navigator initialRouteName="Daily">
<Stack.Screen
name="Daily"
component={Daily}
options={{headerShown: false}}
/>
<Stack.Screen
name="Todos"
component={Todos}
options={{headerShown: false}}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
const Daily = ({navigation}) => {
return (
<View style={globalStyles.overallBackground}>
<Navbar />
<Calendar navigation={navigation} />
</View>
);
};
Todos:
const Todos = ({route, navigation}) => {
return (
<View style={globalStyles.overallBackground}>
<Navbar />
<Button title="back" onPress={()=>navigation.goBack()} ></Button>
</View>
);
};
Where am I going wrong?
Try out putting --
this.props.navigation.goBack()

Open a new screen through a tab screen

I'm trying to show a single screen when someone clicks on a text.
I created a login screen, a single screen called Test, and the main screen with a navigation container that contains two screens inside. And I would like to put inside one of the screens, a clickable text that opens a new screen when clicked.
I'm passing the navigator as a parameter too, but when I try to run my app and I click at the clickable text, I receive this message:
The action 'NAVIGATE' with payload {"name":"Test"} was not handled by
any navigator.
Do you have a screen named 'Test'?
If you're trying to navigate to a screen in a nested navigator, see
https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.
This is a development-only warning and won't be shown in production.
My routes file:
export default class App extends React.Component {
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName='Login' screenOptions={{headerShown: false}}>
<Stack.Screen name='Main' component={Main} />
<Stack.Screen name='Login' component={Login} />
<Stack.Screen name='Test' component={Test} />
</Stack.Navigator>
</NavigationContainer>
);
}
}
Tab Navigator file
const Tab = createBottomTabNavigator();
export default function App ({navigation}){
return (
<NavigationContainer independent={true} >
<Tab.Navigator>
<Tab.Screen
name="Profile"
component={ProfileScreen}
options={{
tabBarLabel: 'Perfil',
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home-outline" color={color} size={size} />
),
}}
/>
<Tab.Screen
name="List"
component={ListScreen}
initialParams={{ navigation: navigation }}
options={{
tabBarLabel: 'List'
}}
/>
</Tab.Navigator>
</NavigationContainer>
);
}
ListScreen function (contains the screen that shows a clickable text)
function ListScreen(param) {
return (
<SafeAreaView style={{ flex: 1, backgroundColor: "#fff" }}>
<LinearGradient
colors={['#000f17', '#0c3552']}
style={styles.main_container}>
<SafeAreaView style={styles.main_subcontainer}>
<List navigate={param}/>
</SafeAreaView>
</LinearGradient>
</SafeAreaView>
);
}
List component
export class List extends Component {
constructor(props) {
super(props);
console.log(this.props.navigate.navigation.navigate);
}
render() {
return (
<View>
<ScrollView>
<TouchableOpacity onPress={() => {
this.props.navigate.navigation.navigate('Test')
}}>
<Text>Click Here</Text>
</TouchableOpacity>
</ScrollView>
</View>
);
}
}

React Native: where to place Navigators for other screens?

My Application has a BottomTabNavigator, each Tab is linked to a component, which is a StackNavigator.
With that implementation, I can easily switch between the tab screens and also see a detailed screen.
Here is the code of my Screen component:
export default function Screen ({props, children}) {
return (
<>
<Stack.Navigator
screenOptions={{
cardShadowEnabled: false,
header: (props) => {
return <Header {...props} />
},
}}
>
<Stack.Screen name="Settings" component={SettingsScreen} />
</Stack.Navigator>
<SafeAreaView style={styles.screen}>
<View style={styles.container}>{ children }</View>
</SafeAreaView>
<TabNavigator i18n={i18n}/>
</>
);
}
In the header component, I have an Icon, which onPress needs to navigate to the SettingsScreen.
I am afraid that I am not sure if this is the right implementation of the SettingsNavigator and if yes, how is possible on click on my header menu to navigate to the SettingsScreen.
Here is my Header.js code:
export default function Header (props, navigation) {
...
return (
<View style={styles.container}>
<View style={styles.link} onPress={navigation.navigate("Settings")}>
<MaterialCommunityIcons name="tune" size={32} />
</View>
</View>
)
};
I get an error:
TypeError: navigation.navigate is not a function.(In
'navigation.navigate("Settings")', 'navigation.navigate' is undefined)
How can I access the navigation from my Header component?
I don't think it's a correct implementation.
Please try like following
<Stack.Navigator
initialRouteName={Routes.SignIn}
screenOptions={{
cardShadowEnabled: false,
header: (props) => {
return <Header {...props} />
},
}}
>
<Stack.Screen name={Routes.SignIn} component={SignInScreen} />
<Stack.Screen name={Routes.ForgotPassword} component={ForgotPasswordScreen} />
<Stack.Screen name={Routes.SignUp} component={SignUpScreen} />
</Stack.Navigator>

navigation.navigate on a button in headerRight of the Stack Navigator

Firstly, I have the same issue as Button linking in headerRight. But their solution was simply using functional over component. I cannot simply switch to functional code as I need to use componentDidMount, so I really need solution for a component based headerRight navigation usage.
Stack
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen
name="Root"
component={BottomTabs}
options={{
headerRight: ({ navigation }) => (
<View>
<Button
onPress={() => navigation.navigate('Profile')}
</Button>
</View>
),
}}
/>
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
);
}
BottomTabs
const BottomTabs = createBottomTabNavigator();
function MyTabs() {
return (
<BottomTabs.Navigator
...
This will bring an error that navigation is not available there. Okay that's right, as you cannot use navigation directly in the definition of the Stack Navigator.
Even using:
headerRight: () => {
return <ProfileButtonScreen/>
},
did not help as on that component I still not have the navigation available.
This is too less info but is already going in the right direction. And finally this gave me the idea about misusing the BottomTabs for the defining of the headerRight.
Stack
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen
name="Root"
component={BottomTabs}
/>
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
);
}
BottomTabs
const BottomTabs = createBottomTabNavigator();
function MyTabs({ navigation, route }) {
navigation.setOptions({
headerRight: () => (
<View>
<Button
onPress={() => navigation.navigate('Profile')}
title="To Profile"
>
</Button>
</View>
),
});
return (
<BottomTabs.Navigator
...
This will now let you have a clickable button on stack navigation header.

React navigation 5 - header is not shown

Trying to update my app to react navigation 5 and been confronting some issues.
First of all, the header does not show up. Snips from the code:
[from App.js]
const Tab = createBottomTabNavigator();
function App() {
return (
<NavigationContainer>
<Tab.Navigator >
<Tab.Screen name="Home" component={HomeScreen} options={{ title:'some title' }}/>
<Tab.Screen name="Upload" component={UploadScreen} />
<Tab.Screen name="Find" component={FindScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
export default App;
and the style of the current screen:
<View style={{flex:1, flexDirection:'column',justifyContent:'space-between'}}>
Here is a screenshot of the app on an Android emulator (and it looks the same on my phone):
As you can see, the header is not shown, the tab navgiation does not right, and so are the buttons (something changed about their background). I did not change anything in the app besides upgrading to react-navigation 5..
Thanks for the help!
Tab navigators do not have header support. You have to wrap your tab navigator inside a stack navigator.
import { createStackNavigator } from "#react-navigation/stack";
// ... other imports
export const App = () => {
return (
<NavigationContainer>
<StackNavigator />
</NavigationContainer>
);
}
const Stack = createStackNavigator();
const StackNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Tabs" component={TabNavigator} />
</Stack.Navigator>
);
}
const Tab = createTabNavigator();
const TabNavigator = () => {
return (
<Tab.Navigator >
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Upload" component={UploadScreen} />
<Tab.Screen name="Find" component={FindScreen} />
</Tab.Navigator>
);
}