React native Stack Navigator goes to the home page the default route (initialroutename) from every page of the app I want to go to previous pages from few pages and disable going to the back page from few pages. Back Handler is not even helping in this case. How can I achieve this
class AppNavigator extends Component {
constructor(props) {
super(props)
this.handleBackButtonClick = this.handleBackButtonClick.bind(this);
}
componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButtonClick);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButtonClick);
}
handleBackButtonClick() {
this.props.navigation.goBack();
return true;
}
render() {
return;
}
}
export default AppNavigator;
Code for Drawer Navigator. All routes are also defined here.
import React from "react";
import { DrawerNavigator } from "react-navigation";
import Home from "./components/home/";
import SideBar from "./components/sidebar";
import Dashboard from "./components/Dashboard/";
import Profile from "./components/Profile"
import Contact from "./components/Contact"
import Terms from "./components/terms"
import Links from "./components/Links"
import Register from "./components/Register"
import Discover from "./components/Discover/";
const Drawer = DrawerNavigator(
{
Home: { screen: Home },
Dashboard: { screen: Dashboard },
Discover: { screen: Discover }
Profile : {screen: Profile},
Contact: { screen: Contact},
Terms: { screen: Terms},
Links: { screen: Links},
Register: { screen: Register,
navigationOptions: {
title: "FirstPage",
header: {
left: null,
}
}, },
},
{
initialRouteName: "Home",
contentOptions: {
activeTintColor: "#e91e63"
},
drawerPosition: 'right',
contentComponent: props => <SideBar {...props} />
}
);
export default Drawer;
Why are you handling a back event? instead, use navigation reset property that will reset your route to 0 and user will never go back because stake is empty
Related
I have created a navigation setup for my application that should start off with a welcome screen on the welcome screen you find two buttons, one for registering and the other for logging in.
When the user registers or logs in he get sent to other screens. I have created a stack navigator between the log in and register screen and put them in a loginFlow constant and another between the welcome screen and the loginFlow constant and the navigation between these screens works, but for some reason the welcome screen doesn't get shown first instead I get the sign up screen (register screen).
Why is that the case and how can i make the welcomeScreen get shown first
import React from "react";
import { View } from "react-native";
import WeclomeScreen from "./app/screens/WelcomeScreen";
import MainScreen from "./app/screens/MainScreen";
import AccountScreen from "./app/screens/AccountScreen";
import { Provider as AuthProvider } from "./app/context/AuthContext";
import { createMaterialBottomTabNavigator } from "react-navigation-material-bottom-tabs";
import SignupScreen from "./app/screens/SignupScreen";
import { createAppContainer, createSwitchNavigator } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import ResultShowScreen from "./app/screens/ResultShowScreen";
import ResolveAuthScreen from "./app/screens/ResolveAuthScreen";
import SigninScreen from "./app/screens/SigninScreen";
import ArticleSaveScreen from "./app/screens/ArticleSaveScreen";
import { setNavigator } from "./app/navigationRef";
const articleListFlow = createStackNavigator({
Main: MainScreen, // screen with diffrent articles categories
ResultsShow: ResultShowScreen, // article details screen
});
const loginFlow = createStackNavigator({
Signup: SignupScreen,
Signin: SigninScreen,
});
loginFlow.navigationOptions = () => {
return {
headerShown: false,
};
};
articleListFlow.navigationOptions = {
title: "News Feed",
tabBarIcon: ({ tintColor }) => (
<View>
<Icon style={[{ color: tintColor }]} size={25} name={"ios-cart"} />
</View>
),
activeColor: "#ffffff",
inactiveColor: "#ebaabd",
barStyle: { backgroundColor: "#d13560" },
};
const switchNavigator = createSwitchNavigator({
ResolveAuth: ResolveAuthScreen,
MainloginFlow: createStackNavigator({
WelcomeScreen: WeclomeScreen,
loginFlow: loginFlow,
}),
mainFlow: createMaterialBottomTabNavigator(
{
articleListFlow: articleListFlow,
ArticleSave: ArticleSaveScreen, // we dont need this one
Account: AccountScreen,
},
{
activeColor: "#ffffff",
inactiveColor: "#bda1f7",
barStyle: { backgroundColor: "#6948f4" },
}
),
});
const App = createAppContainer(switchNavigator);
export default () => {
return (
<AuthProvider>
<App
ref={(navigator) => {
setNavigator(navigator);
}}
/>
</AuthProvider>
);
};
here is the content of ResolveAuthscreen :
import React, { useEffect, useContext } from "react";
import { Context as AuthContext } from "../context/AuthContext";
const ResolveAuthScreen = () => {
const { tryLocalSignin } = useContext(AuthContext);
useEffect(() => {
tryLocalSignin();
}, []);
// not returning anything since just waiting to check the token
// will transition to signin or signup very quickly
return null;
};
export default ResolveAuthScreen;
As you have mentioned in your comments, you have an issue in your tryLocalSignin method. In that method, if there is no any token, you are navigating the user to the Signup screen. Instead of navigating to the Signup screen, navigate to the WelcomeScreen screen like:
const tryLocalSignin = (dispatch) => async () => {
const token = await AsyncStorage.getItem("token");
if (token) {
dispatch({ type: "signin", payload: token });
navigate("Main");
} else {
navigate("WelcomeScreen");
}
};
I am a beginner in react native and very confused about navigation between two screens after x second delay.
How can I move from splash screen to login screen after some seconds in react native?
this is how iv'e achieved that by having a splashscreen as inital route in stackNavigator and then in componentDidMount after 3 secs im navigating to LoginScreen.
{
initialRouteName: "SplashScreen"
}
this is inside the stack navigator.
and inside the componentDidMount of the splashScreen class im doing this
componentDidMount(){
window.setTimeout(async () => {
const token = await isSignedIn();
this.props.navigation.navigate(token ? 'HomeScreen' : 'OnBoardingScreen');
}, 3000);
}
so what im doing is, im checking if token is stored in asyncStorage by the isSignedIn(). and if token is present then im navigating to HomeScreen or LoginScreen respectively after 3 secs.(3000 denotes in ms)
Feel free for doubts.
UPDATE:
import React, { Component } from 'react';
import { View, StatusBar } from 'react-native';
import { isSignedIn } from '../../services/auth';
import Animation from "lottie-react-native";
import styles from './SplashScreenStyle';
export default class SplashScreen extends Component {
componentDidMount() {
StatusBar.setHidden(true);
this._playAnimation();
window.setTimeout(async () => {
const token = await isSignedIn();
this.props.navigation.navigate(token ? 'HomeScreen' : 'OnBoardingScreen');
}, 2120);
}
state = {
animation: null,
};
_playAnimation = () => {
if (!this.state.animation) {
this._loadAnimationAsync();
} else {
this.animation.play();
}
};
_loadAnimationAsync = async () => {
let result = await fetch(
"https://assets1.lottiefiles.com/packages/lf20_vi3n1R.json"
)
.then(data => {
return data.json();
})
.catch(error => {
console.error(error);
});
this.setState({ animation: result }, this._playAnimation);
};
render() {
return (
<View style={styles.animationContainer}>
{this.state.animation && (
<Animation
ref={animation => {
this.animation = animation;
}}
style={{ width: 200, height: 200, backgroundColor: "transparent" }}
source={this.state.animation}
/>
)}
</View>
);
}
}
I'm actually working on single page navigation, tab navigation and Drawer navigation by using react native navigation.
After the drawer implementation is done, single page navigation is working fine but the whole application is getting crashed after clicking on a login button.
Take a look at the code that I have written :
app.js:
import { Navigation } from 'react-native-navigation';
import AuthScreen from './src/screens/Auth/Auth';
import SharePlaceScreen from './src/screens/SharePlace/SharePlace';
import FindPlaceScreen from './src/screens/FindPlace/FindPlace';
import SideDrawer from "./src/screens/SideDrawer/SideDrawer";
// register screens
Navigation.registerComponent('example.AuthScreen', () => AuthScreen);
Navigation.registerComponent('example.SharePlaceScreen', () => SharePlaceScreen);
Navigation.registerComponent('example.FindPlaceScreen', () => FindPlaceScreen);
Navigation.registerComponent('example.SideDrawer', () => SideDrawer);
// start a app
Navigation.startSingleScreenApp({
screen: {
screen:'example.AuthScreen',
title:"Login"
}
})
startMainTab.js
import { Navigation } from 'react-native-navigation';
import {Dimensions} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
const wDim = Dimensions.get('window');
const fixedWidth = Math.round(wDim.width * wDim.scale * 0.8);
const startTab = () =>{
Promise.all([
Icon.getImageSource("map",30),
Icon.getImageSource("share",30),
Icon.getImageSource("menu",30),
]).then(sources =>{
Navigation.startTabBasedApp({
tabs: [
{
screen:"example.AuthScreen",
label : "Find Place",
title : "Find Place",
icon : sources[0],
navigatorButtons:{
leftButton:[
{
icon:sources[2],
title:"Menu",
id:"sideDrawerToggle"
}
]
}
},
{
screen:"example.AuthScreen",
label : "Share Place",
title : "Share Place",
icon : sources[1],
navigatorButtons:{
leftButton:[
{
icon:sources[2],
title:"Menu",
id:"sideDrawerToggle"
}
]
}
}
],
drawer: {
left: {
screen:"example.SideDrawer"
}
}
});
})
}
export default startTab;
SideDrawer.js
import React, { Component } from 'react';
import {View,Text,Dimensions,StyleSheet} from 'react-native';
class SideDrawer extends Component{
render(){
return(
<View >
<Text
style={[styles.container,{width:Dimensions.get("window").width*0.8}]}>
On SideDrawer
</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container:{
paddingTop:22,
backgroundColor:"white",
flex:1
}
})
export default SideDrawer;
sharePlace.js
import React,{ Component } from 'react';
import {View,Text} from 'react-native';
class SharePlaceScreen extends Component{
constructor(props){
super(props);
props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
}
onNavigatorEvent = event => {
console.log(events)
if(event.type === "NavBarButtonPress"){
if(event.id === "sideDrawerToggle"){
this.props.navigator.toggleDrawer({
side: 'left'
})
}
}
}
render(){
return(
<View>
<Text>On Share place screen</Text>
</View>
);
}
}
export default SharePlaceScreen;
leftButton: [
{
icon: sources[2],
title: "Menu",
id: "sideDrawerToggle"
}
]
This should be ,
leftButtons: [
{
icon: sources[2],
title: "Menu",
id: "sideDrawerToggle"
}
]
Follow this link :
https://wix.github.io/react-native-navigation/#/adding-buttons-to-the-navigator.
Hope this helps you. :)
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 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' });