I'm sorry for the what might turn out to be a very stupid question, but for some time now I'm struggling with the following issue, but I'm new to react-native.
I create a react-native app in which I implement the react-navigation-drawer navigation precisely as in the example.
What happens is that whenever I open the App the drawer is opened. The same things happens when i copy and paste the example from here: https://reactnavigation.org/docs/en/drawer-based-navigation.html
This makes me think I'm missing something with the dependencies. I've upgraded all i could think of from the needed librabries. My CPU is not a good one so I'm using my Android phone for testing.
I also get the warning "componentWillMount has been renamed..." when i use the react-navigation-drawer.
If you could help guide me to some information that would be helpful!
Thank you all in advance!
Below is some code for an example:
import React from 'react';
import { FlatList, ActivityIndicator, Text, Header, Image, View, ScrollView, Alert, TouchableWithoutFeedback, TouchableOpacity, TouchableHighlight, StyleSheet } from 'react-native';
import {Button, Icon, ThemeProvider} from 'react-native-elements';
import {createAppContainer, DrawerNavigator, withNavigation} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import {createDrawerNavigator, DrawerActions, DrawerLayoutAndroid} from 'react-navigation-drawer';
.....
const Screen1PageScreenStack = createStackNavigator({
Screen1Page: {
screen: Screen1Page,
}
},{
navigationOptions: ({ navigation }) => ({
initialRouteName: 'Screen1Page',
headerMode: 'screen',
drawerLabel: 'HOME',
drawerBackgroundColor: '#0000FF',
}
)
});
const Screen2PageScreenStack = createStackNavigator({
Screen2Page: {
screen: Screen2Page,
}
},{
navigationOptions: ({ navigation }) => ({
initialRouteName: 'Screen2Page',
headerMode: 'screen',
drawerLabel: 'Categories',
}
),
});
const appNavigator = createDrawerNavigator({
Screen1Page: {
name: 'Screen1PageScreenStack',
screen: Screen1PageScreenStack,
},
Screen2Page: {
name: 'Screen2PageScreenStack',
screen: Screen2PageScreenStack,
}
});
const MyDrawerStrugglesApp = createAppContainer(appNavigator);
export default MyDrawerStrugglesApp ;
You can try this code to keep your drawer hidden for required screen :
const Nav = createDrawerNavigator(
{
Home: {
screen: AppLogin,
navigationOptions:{
drawerLockMode: 'locked-closed',
drawerLabel: <Hidden />
},
},
}
);
Your Hidden class should be as follows :
class Hidden extends React.Component {
render() {
return null;
}
}
You can change the drawerLockMode value to keep the drawer opened or closed - Refer here for different values.
Also you can refer this SO answer here for avoiding the componentWillMount deprecation error. Hope this helps !
With react-navigation V5 you can pass the openByDefualt prop
<Drawer.Navigator
initialRouteName="Home"
openByDefault>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Notifications" component={NotificationsScreen} />
</Drawer.Navigator>
With react-navigation v6 all you need to do is pass defaultStatus="closed" prop directly to Drawer.Navigator. The app will always load with the drawer closed.
Related
How The App works!
I have an app that shows a list of names and after that shows the meaning of the Name depends on some preference the user choose it from a dropDowns.
So in total there is a Main of 3 Screens!
First: is the UI screen that asks user to choose data,
Second: is the screen that holds a list contains names, I list them using a FlatList (BTW the data retrives from a SqLite -not important-)
Third: is the Screen that shows the name's meaning,
I am navigating from the "Main-Screen" to the "NameList-Screen" then To the "NameMeaning-Screen",
The navigation to the "NameMeaning-Screen" done by pressing on an item from the List.
Till here the app working nicely!
I decided to add a new feature to the app and that to show all the names i have in my DB and show it in a screen that have two Tabs, The first tab shows male's names and the second tab shows the female's names.
I did that step too.
But What am facing now is!
I want to navigate from that tabs when pressing on an item from the flatList, and navigate to the "Third Screen" I mentioned above the name's meaning!
But it gave error that, there is no such screen called "NameMeaing" and then it says " Name screen Its not handled by any navigator", So as much as i understand, when am in the Tabs the program have no access to the stack Navigator and cuz of this it gives that error.
As much as i was able to find on Web, There is examples of navigating from tabs to another stack screens, but in the all the examples, the tabs were the main screen in the applicaiton, but in my case i reach the tabs after pressing a certain button and navigate to another stacked screen.
As a soluation for the problem i thought about creating a secondry stack navigator inside my Tabs.js file that contains the tabs but i couldnt, then i thought i should create a Tab navigator in my App.js adding it to my stack navigator that already exists there and compine them in a navigator container. Maybe this is the soluation but i couldnt complete the code and connect the dots. Any help please?!
This is a video of the app while working (The scenario)
https://youtu.be/dBLNF5zMCt0
This is the Error it shows:
Error when i try to navigate from a tab screen to another different screen
This is App.js file
import 'react-native-gesture-handler';
import React, {Component} from 'react';
import {createStackNavigator} from 'react-navigation-stack';
import {createAppContainer} from 'react-navigation';
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
import MainScreen from './MainScreen';
import NamesList from './NamesList';
import NameMeaning from './NameMeaning';
import NameListWithTabsAgirlAboy from './NameListWithTabsAgirlAboy';
const App = createStackNavigator(
{
MainScreen: {
screen: MainScreen,
navigationOptions: {
header: null,
},
},
NamesList: {
screen: NamesList,
navigationOptions: {
header: null,
},
},
NameListWithTabsAgirlAboy: {
screen: NameListWithTabsAgirlAboy,
navigationOptions: {
header: null,
},
},
NameMeaning: {
screen: NameMeaning,
navigationOptions: {
header: null,
},
},
},
{
initialRouteName: 'MainScreen',
}
);
export default createAppContainer(App);
This is NameMeaninng.js file
class NameMeaning extends Component {
constructor(props) {
super(props);
}
render() {
const {navigation} = this.props;
return(
<SafeAreaView style= {styles.container}>
<Text style={styles.title}>معنى اسم {JSON.stringify(navigation.getParam('nameTitle', 'NO-ID'))}</Text>
<ScrollView style={styles.scrollView}>
<Text style={styles.text}>
{JSON.stringify(navigation.getParam('explaination', 'NO-ID'))}
</Text>
</ScrollView>
</SafeAreaView>
);
}
}
this is parts of Tabs.js file
This file have three classes in totall. BoysScreen, GirlsScreen and Tabs classes..
class BoysScreen extends React.Component {
constructor(props) {
super(props);
const {navigation} = this.props;
}
render() {
let FlatListNames = [];
FlatListNames = boysNames();
const {navigation} = this.props;
function Item({ title }, {navigation}) {
return (
<View style = {StyleSheet.item}>
<Text styel = {styles.title}> {title} </Text>
<Text style ={StyleSheet.explain}>اضغط للشرح</Text>
</View>
)
}
function boysNames() {
var boysNamesList = [];
db.transaction(tx => {
// boys names
tx.executeSql('SELECT ID, Name, Explanation FROM Names WHERE NameSex=?', ["لـ طفلي"], (tx, results) => {
for (let i = 0; i < results.rows.length; ++i) {
boysNamesList.push(results.rows.item(i));
}
});
}); // DB transaction
return boysNamesList;
};
return(
<View style= {styles.container}>
<FlatList
data={FlatListNames}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) =>
<TouchableOpacity
onPress = {() => {this.props.navigation.navigate('NameMeaning',{
nameTitle : item.Name,
nameId : item.ID,
explaination : item.Explanation,
});
}}
>
<Item title = {item.Name}/>
</TouchableOpacity>
}
/>
</View>
);
}
}// ends of BoysScreen Class
class Tabs extends React.Component {
constructor(props){
super(props);
}
render() {
const Tab = createMaterialTopTabNavigator();
// I have tried to create a stack here but it gave errors and couldnt solve it
//cont Stack = createStackNavigator();
return(
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name ="FemaleNames" component = {GirlsScreen} /> //GirlsScreen is a class
<Tab.Screen name = "MaleNames" component = {BoysScreen} /> // BoysScreen is a class
</Tab.Navigator>
// I have tried to import NameMeanig class and navigate to it like this, but it gaves errors too.
//<Stack.Screen name="Home" component={NameMeaning} />
</NavigationContainer>
);
}
Thanks in advance, any help of how i can build this algorithm is appricated really..
It was a problem with version compatibility, i was using React navigation V4 and V5 alltogether, After Searching more i have solved it in this way, Changing App.js and compine all the stacks and tabs navigators in App.js
Credit to this guy : https://www.youtube.com/watch?v=nQVCkqvU1uE
import 'react-native-gesture-handler';
import React, {Component} from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
import MainScreen from './App/components/Home/MainScreen';
import NamesList from './App/components/NameList/NamesList';
import NameMeaning from './App/components/NameMeaning/NameMeaning';
import GirlNamesScreen from './App/components/NameList/GirlsNamesTab';
import BoysNamesScreen from './App/components/NameList/BoysNamesTab';
const MainStack = createStackNavigator();
const MainStackScreen = () => (
<MainStack.Navigator>
<MainStack.Screen
name="MainScreen"
component={MainScreen}
options={{ title: "Main Screen title" }}
/>
<MainStack.Screen
name="NamesList"
component={NamesList}
options={{ title: "NamesList Screen title" }}
/>
<MainStack.Screen
name="NameMeaning"
component={NameMeaning}
options={{ title: "NameMeaning Screen title" }}
/>
<MainStack.Screen
name="TabsScreen"
component={TabsScreen}
options={{ title: "TabsScreen Screen title" }}
/>
</MainStack.Navigator>
);
const Tabs = createMaterialTopTabNavigator();
const GirlNamesStack = createStackNavigator();
const BoysNamesStack = createStackNavigator();
const GirlNamesStackScreen = () => (
<GirlNamesStack.Navigator>
<GirlNamesStack.Screen name="GirlsNames" component={GirlNamesScreen} />
</GirlNamesStack.Navigator>
);
const BoysNamesStackScreen = () => (
<BoysNamesStack.Navigator>
<BoysNamesStack.Screen name="BoysNames" component={BoysNamesScreen} />
</BoysNamesStack.Navigator>
);
const TabsScreen = () => (
<Tabs.Navigator>
<Tabs.Screen name="BoysNames" component={BoysNamesStackScreen} />
<Tabs.Screen name="GirlsNames" component={GirlNamesStackScreen} />
</Tabs.Navigator>
);
const RootStack = createStackNavigator();
const RootStackScreen = () => (
<RootStack.Navigator headerMode="none">
<RootStack.Screen
name="Main"
component={MainStackScreen}
options={{
animationEnabled: false
}}
/>
</RootStack.Navigator>
);
export default () => {
return (
<NavigationContainer>
<RootStackScreen/>
</NavigationContainer>
);
};
So basically i'm in the process of learning react native. I'm using the react navigation package and I just want to display a simple header title on my stack navigator but the title cuts off. Stack nav title
This is my App.js
import React from 'react';
import { View, Text } from 'react-native';
import { createStackNavigator, createAppContainer} from 'react-navigation'
import HomeScreen from './screens/HomeScreen'
import DetailsScreen from './screens/DetailsScreen'
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home'
}
);
const AppContainer = createAppContainer(RootStack)
export default class App extends React.Component {
render(){
return<AppContainer />
}
}
and this is my HomeScreen.js
import React from 'react'
import {Button, View, Text } from 'react-native'
export default class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
}
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screeeen</Text>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details')}
/>
</View>
)
}
}
It doesnt look like this on my friends phones. I'm using a OnePlus 6 with android 9. They are on older versions of android could that be causing something?
Turns out this is a specific problem affecting OnePlus user who has chosen to use the font OnePlus Slate instead of for exmaple robot. Changing the font in the phone fixes the problem, alternatively you force the usage of a font in the app and it should work as well
I got the same problem running on a OnePlus phone and solved it without the font loader but style with the navigation option in headerTitleStyle width like so:
import { Dimensions } from 'react-native';
const WIDTH = Dimensions.get('window').width;
export const MyStackNav = createStackNavigator(
{
Tab1: {
screen: Tab1,
navigationOptions: ({ navigation }) => ({
headerTitle: `${navigation.state.routeName} page`,
headerTitleStyle: {
width: WIDTH - 75,
},
}),
},
...more code
}
A similar issue also occurs in various components like button in one plus devices. One way to solve it by giving some minimum width to the label style, so that you don't have to switch the font family, helps if you are using some custom fonts
Solution: width: '100%' or some fixed value like minWidth: 100
Code example in drawer navigation
<DrawerItem
labelStyle={{ minWidth: 100 }}
label={`Orders`}
onPress={() => {}}
/>
I recreated the Drawer Navigation following this code: https://github.com/mariodev12/react-native-menu-drawer-navigator
Everything works correctly but now I do not know how to handle the native button to go back .. I would like to always return to the previous page, but if you press twice in the home exit the app.
This is my Code:
App.js
import React from 'react';
import {StackNavigator} from 'react-navigation';
import DrawerStack from './src/stacks/drawerStack';
const Navigator = StackNavigator({
drawerStack: {screen: DrawerStack}
}, {
headerMode: 'none',
initialRouteName: 'drawerStack'
})
export default Navigator
drawerStack.js
import React from 'react'
import {StackNavigator, DrawerActions} from "react-navigation";
import {Text, View, TouchableOpacity} from 'react-native';
import Home from "../components/home";
import DrawerScreen from "./drawerScreen";
const DrawerNavigation = StackNavigator({
DrawerStack: {screen: DrawerScreen}
}, {
headerMode: 'float',
navigationOptions: ({navigation}) => ({
headerStyle: {
backgroundColor: 'rgb(255,45,85)',
paddingLeft: 10,
paddingRight: 10
},
title: 'Home',
headerTintColor: 'white',
headerLeft: <View>
<TouchableOpacity
onPress={() => {
if (navigation.state.isDrawerOpen === false) {
navigation.dispatch(DrawerActions.openDrawer());
} else {
navigation.dispatch(DrawerActions.closeDrawer());
}
}}>
<Text>Menu</Text>
</TouchableOpacity>
</View>
})
})
export default DrawerNavigation;
drawerScreen.js
import {DrawerNavigator} from 'react-navigation'
import Home from '../components/home';
import Login from '../components/login';
import Contacts from '../components/contacts';
import News from '../components/news';
const DrawerScreen = DrawerNavigator({
Home: {screen: Home},
Login: {screen: Login},
Contacts: {screen: Contacts},
News: {screen: News}
}, {
headerMode: 'none',
initialRouteName: 'Home'
})
export default DrawerScreen;
news.js "Example of one page"
import React from "react";
import {Text, View} from 'react-native';
export default class News extends React.Component {
render() {
return (
<View>
<Text> Here Leave the News!! </Text>
</View>
);
}
}
Now, how do I insert the back button in the header instead of the classic menu (DrawerStack) for only the 'News.js' page?
In Android you have to handle back button actions by yourself with BackHandler from react-native.
First of all
import { BackHandler } from 'react-native';
in ComponentDidMount add an event listener to listen for backpress:
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.onBackPress);
}
in ComponentwillUnmount make sure you remove the listener:
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.onBackPress);
}
then
onBackPress = () => {
//inside here do what you want with single back button
}
Checkout this link too:
https://reactnavigation.org/docs/en/drawer-based-navigation.html
If you want to go back to previous Screen with back button drawer navigation isn't for you and you should try to use Stack Navigator.
You need create the button in your news screen too, like this.
import React from "react";
import {Text, View} from 'react-native';
export default class News extends React.Component {
static navigationOptions = ({navigation}) => {
return {
headerLeft: --- PUT HERE YOU CUSTOM BUTTON (Use navigation.goBack() in onPress)
}
}
render() {
return (
<View>
<Text> Here Leave the News!! </Text>
</View>
);
}
}
To make better, you can create a new screen with only your custom navigation options.
I created a simple Android app that changes navigates when the text is pressed. The app runs properly but when I touch the text, the contents do not change and no navigation is observed. You can have a look at the error here. I have also provided the code:
import React, { Component, PropTypes } from 'react';
import { Navigator, Text, TouchableHighlight, View, AppRegistry} from
'react-native';
export default class SimpleNavigationApp extends Component {
constructor(props){
super(props);
this.state={
title: 'My Initial Scene',
}
}
render() {
return (
<Navigator
initialRoute={{ title: 'My Initial Scene', index: 0 }}
renderScene={(route, navigator) =>
<MyScene
title={route.title}
// Function to call when a new scene should be displayed
onForward={ () => {
const nextIndex = route.index + 1;
navigator.push({
title: 'Scene ' + nextIndex,
index: nextIndex,
});
}}
// Function to call to go back to the previous scene
onBack={() => {
if (route.index > 0) {
navigator.pop();
}
}}
/>
}
/>
)
}
}
class dhrumil extends Component {
static propTypes = {
title: PropTypes.string.isRequired,
onForward: PropTypes.func.isRequired,
onBack: PropTypes.func.isRequired,
}
render() {
return (
<View>
<Text>Current Scene: { this.props.title }</Text>
<TouchableHighlight onPress={this.props.onForward}>
<Text>Tap me to load the next scene</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this.props.onBack}>
<Text>Tap me to go back</Text>
</TouchableHighlight>
</View>
)
}
}
AppRegistry.registerComponent("dhrumil",()=>dhrumil);
As you can see in the error, the title is also not displayed after the text "My Current Scene: ". How can I solve this?
First, your export default class SimpleNavigationApp is never called.
You should put it in another js file and import it to dhrumil class
.
Second,
import { Navigator } from 'react-native' is no longer supported.
Read https://facebook.github.io/react-native/docs/navigation.html for detailed navigation documentation.
I have a stack navigator set up in the following way
const wishlizt = StackNavigator({
Splash: {screen: SplashScreen},
SignIn: {screen: SignInScreen},
SignUp: {screen: SignUpScreen},
Profile: {screen: ProfileScreen},
Home: {screen: MainScreenNavigator},
Chat: {screen: ChatScreen}
},
{
navigationOptions: {
title: 'Wishlizt',
header: {
style: {
backgroundColor: Colors.bgBrand,
elevation: null,
},
titleStyle: {
color: Colors.lightest
},
right: <HeaderRight />
}
},
initialRouteName: 'Splash'
});
As you can see I use a component HeaderRight in my header which contains some icons - settings cog, profile, etc. I want to be able to navigate from those icons' TouchableOpacity onPress method. But the navigation prop 'this.props.navigation' is missing in that component.
The official documentation page has this code sample on how to call navigate on the top level component and recommends using 'ref'
const AppNavigator = StackNavigator(SomeAppRouteConfigs);
class App extends React.Component {
someEvent() {
// call navigate for AppNavigator here:
this.navigator && this.navigator.dispatch({ type: 'Navigate', routeName, params });
}
render() {
return (
<AppNavigator ref={nav => { this.navigator = nav; }} />
);
}
}
I am unable to see how this can work in my example. Can anyone help on this? Thanks
Huge
The header property can be a function as well as an object. When it is a function, the navigation object is passed in as the first parameter, it can then be passed to the HeaderRight component as a prop.
navigationOptions: {
header: (navigation) => {
return {
style: {
backgroundColor: Colors.bgBrand,
elevation: null,
},
titleStyle: {
color: Colors.lightest
},
right: (<HeaderRight
navigation={navigation}
/>),
};
},
},
I don't know if this helps, I am researching why my call isn't working either in react-navigation. But your braces are messed up in your example. You have initial route name inside of the navigation options, which might be right, but your indenting shows a whole other story...
If you want to "call navigate on the top level" or if you don't have the navigation prop available you can do so as described here: https://reactnavigation.org/docs/navigating-without-navigation-prop/
Use ref in the NavigationContainer:
// App.js
import { NavigationContainer } from '#react-navigation/native';
import { navigationRef } from './RootNavigation';
export default function App() {
return (
<NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
);
}
Create RootNavigation.js where you define your dispatches:
// RootNavigation.js
import { createNavigationContainerRef } from '#react-navigation/native';
export const navigationRef = createNavigationContainerRef()
export function navigate(name, params) {
if (navigationRef.isReady()) {
navigationRef.navigate(name, params);
}
}
// add other navigation functions that you need and export them
You can then use your RootNavigation to navigate to the desired screen from anywhere:
// any js module
import * as RootNavigation from './path/to/RootNavigation.js';
// ...
RootNavigation.navigate('ChatScreen', { userName: 'Lucy' });