Remove screen from stack navigator - react-native

I’ve observed Back button logic works seeing the sequence of screens in the stack. I’ve a Drawer navigator placed inside stack navigator.
On top of the stack I’ve Splash screen. On Dashboard when I press back button it takes me to splash screen.
How can I remove splash screen from stack after entering in the app, So when I press back button Dashboard it will EXIT the app instead of taking to SPLASH SCREEN.
/* #flow */
import React from "react";
import { Platform, Text } from "react-native";
import { Root } from "native-base";
import { StackNavigator, DrawerNavigator} from "react-navigation";
import Register from "./components/Register";
import Available from "./components/Available";
import Splash from "./components/splash/“;
import SideBar from "./components/sidebar";
import Discover from "./components/Discover/";
import Dashboard from "./components/Dashboard/";
import Contact from "./components/Contact"
const Drawer = DrawerNavigator(
{
Dashboard: { screen: Dashboard },
Discover: { screen: Discover },
Contact: { screen: Contact},
},
{
navigationOptions: {
gesturesEnabled: false,
},
initialRouteName: "Dashboard",
contentOptions: {
activeTintColor: "#e91e63"
},
drawerPosition: 'right',
contentComponent: props => <SideBar {...props} />
}
);
const AppNavigator = StackNavigator(
{
Splash: { screen: Splash },
Drawer: { screen: Drawer },
Available: { screen: Available },
Register: { screen: Register },
},
{
// initialRouteName: “Splash”,
headerMode: "none",
}
);
export default () =>
<Root>
<AppNavigator />
</Root>;

One solution would be to reset the stack inside the splash screen component and redirect the user to the screen that you prefer:
import { NavigationActions } from 'react-navigation'
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Drawer'})
]
})
this.props.navigation.dispatch(resetAction)
For newer versions of react-navigation :
import { StackActions, NavigationActions } from 'react-navigation';
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Profile' })],
});
this.props.navigation.dispatch(resetAction);
Link to the official documentation

One of the simplest solutions would be, replace current screen with new screen so user won't be allowed to go back.
const SplashScreen: () => {
...
navigation.replace("LoginScreen"); // Move forward and Remove this screen from stack
see https://reactnavigation.org/docs/stack-actions/#replace

I solved it using this
code:
const prevGetStateForActionHomeStack = HomeStack.router.getStateForAction;
HomeStack.router = {
...HomeStack.router,
getStateForAction(action, state) {
if (state && action.type === 'ReplaceCurrentScreen') {
const routes = state.routes.slice(0, state.routes.length - 1);
routes.push(action);
return {
...state,
routes,
index: routes.length - 1,
};
}
return prevGetStateForActionHomeStack(action, state);
},
};
replaceScreen = () => {
const { locations, position } = this.props.navigation.state.params;
this.props.navigation.dispatch({
key: 'NearMeMap',
type: 'ReplaceCurrentScreen',
routeName: 'NearMeMap',
params: { locations, position },
});
};
Also if you need in-depth explanation of the code, watch this short video here

In react-navigation 5.x version. If you want to open new screen and remove previous stack screen, you can write: -
navigation.dispatch(StackActions.replace('screen_name', {params: {}}));
The replace action allows to replace a route in the navigation state. You can import it as:-
import { StackActions } from '#react-navigation/native';
If you want to perform other actions on stack navigation check out this link-
https://reactnavigation.org/docs/stack-actions

useEffect(() => {
setTimeout(() => {
navigation.reset({
index:0,
routes:[
{
name:"Welcome",
// params:{key:'param'},
},
],
});
}, 1000);},[]);
You can also trigger the this onPress like:
onPress={()=>navigation.reset({
index:0,
routes:[
{
name:"NameOfScreen",
// params:{key:'param'},
},
],
})}

Related

React Navigation - Jumping between tabs

Hello guys I have 5 Containers in my tab bar and I would like to know if there is an option to return to the main screen if I select another tab container.
So I have the following
https://snack.expo.io/#react-navigation/stacks-in-tabs-v3
While I am in Home tab I click on Go to Details and then I switch to Settings tab. If I return to Home container I want to see the default screen which is HomeScreen
Any option?
You can redefine the tabBarOnPress of the navigationOptions of each StackNavigator like so:
const stacks = [
{ Home: HomeScreen, Details: DetailsScreen },
{ Settings: SettingsScreen, Details: DetailsScreen }
].reduce((stacksObj, stack) => {
const initialRoute = Object.keys(stack)[0];
stacksObj[initialRoute] = createStackNavigator(
stack,
{
navigationOptions: {
tabBarOnPress: ({ navigation }) => navigation.navigate({
routeName: initialRoute,
action: navigation.popToTop()
})
}
}
);
return stacksObj
}, {});
export default createAppContainer(createBottomTabNavigator(
stacks,
{ /* same defaultNavigationOptions as the snack example */ }
));
Cause your DetailScreen is nested in stack Home, you must navigate one more level to that screen
_navigateHome = () => {
const navigateAction = NavigationActions.navigate({
routeName: 'Home',
action: NavigationActions.navigate({ routeName: 'Home' }),
});
this.props.navigation.dispatch(navigateAction);
}
Looks the api has changed , the new way to achieve this is :
import { CommonActions } from '#react-navigation/native';
navigation.dispatch(
CommonActions.navigate({
name: 'Profile',
params: {
user: 'jane',
},
})
);

How to get header button in react native

I have created a different class for navigation to maintain the state of loggedIn and loggedOut user as follows:-
import React from "react";
import { createStackNavigator, createSwitchNavigator, DrawerNavigator } from "react-navigation";
import DrawerContent from "../views/Sidebar"
import Profile from '../views/Profile';
import Extra from '../views/Extra';
import SignIn from '../views/SignIn';
import Home from '../views/Home';
import Info from '../views/Info';
import Logout from '../views/Logout';
export const SignedIn = createStackNavigator({
Home: {
screen: Home,
},
Profile: {
screen: Profile,
},
Extra: {
screen: Extra,
}
});
export const SignedOut = createStackNavigator({
SignIn: {
screen: SignIn,
navigationOptions: {
title: "Sign Up",
headerRight: <Text>Hi</Text> //calling this gives an error
}
},
});
export const RootNavigator = (signedIn = false) => {
return createSwitchNavigator(
{
SignedIn: {
screen: SignedIn,
navigationOptions: {
gesturesEnabled: false
}
},
SignedOut: {
screen: SignedOut,
navigationOptions: {
gesturesEnabled: false
}
}
}, {
headerMode: "none",
mode: "modal",
initialRouteName: signedIn ? "SignedIn" : "SignedOut"
}
);
};
I want to create a button in navigation bar on signUp screen but it is giving an error like :-
header Title is easily shown onto screen but the right and left button doesn't seems to be appear. Any help on this.
Your header button must be a component
The way you are using is not pointing to a valid component
To do that either create a new component 'HeaderRight' and import it like you did for the 'Home' component,then point your headerRight property to it
Like headerRight:HeaderRight
Or simply wrap your text element within parenthesis like this
headerRight:(<Text>Hi</Text>)
Try and tell me if it is solved
Best regards

navigating user on notification click app in background/foreground

I'm using REACT-NATIVE-FCM.
My app has drawer navigator inside stack navigator in App.js.
On notification click from notification tray I want user to directly go to certain Screen.
Registering FCM events in Home page only work if app is closed, while in app in foreground the events are not called.It just takes you to the last open Screen.
I have to register FCM events on every Screen, which doesn’t look ok to me. So I have the solution to register FCM events in App.js since App.js is called from index.js while initializing the App but I’m unable to use this.props.navigation.navigate in App.js.
Using react navigation how can we redirect user just after stack is declared.
APP.JS
const Drawer = DrawerNavigator(
{
Dashboard: { screen: Dashboard },
Screen1: { screen: Screen1 },
Screen2: { screen: Screen2},
Screen3: { screen: Screen3},
},
{
navigationOptions: {
gesturesEnabled: false,
},
initialRouteName: "Dashboard",
contentOptions: {
activeTintColor: "#e91e63"
},
drawerPosition: 'right',
contentComponent: props => <SideBar {...props} />
}
);
const AppNavigator = StackNavigator(
{
Home: { screen: Home },
Drawer: { screen: Drawer },
ScreenABC: { screen: ScreenABC },
ScreenXYZ: { screen: ScreenXYZ }
},
{
headerMode: "none",
}
);
export default () =>
<Root>
<AppNavigator />
</Root>;
//CALLED WHEN APP IN FOREGROUND
this.notificationListener = FCM.on(FCMEvent.Notification, async (notif) => {
//alert('FCM.on: ' + JSON.stringify(notif));
if(notif.routeValue == 1)
{
this.props.navigation.navigate("Screen1")}
});
//CALLED WHEN APP IN BACKGROUND
FCM.getInitialNotification().then(notif => {
});
If you want to really go to a certain screen no matter what. You should at least reset your navigator state before you call navigate.
Or you can also do is creating a custom action, dispatch this action and return a correct navigator state.
Here is how I reset my navigator state to home:
export const homeNav = (state, action) => {
let index;
let routes;
switch (action.type) {
case types.RESET_HOME_NAV:
routes = [...state.routes];
for (let index = state.index; index > 0; --index) {
routes.pop();
}
return {
...state,
routes,
index: 0,
};
default:
return NavigatorHome.router.getStateForAction(action, state);
}};

How to implement auth flow in react native with react navigation?

Hi guys need help over Login flow, I write a code for auth flow but facing some weird issue like.
Right now what is happening I have login page while clicking on signIn button, I am sending the user to auth screen but if user click on back button then he moves to login screen again, and this is wrong, if user is login then why it's again move to login screen.
Here is code for it this is my route.js
import React from 'react';
import { StackNavigator, DrawerNavigator } from 'react-navigation'
import loginScreen from '../containers/login/loginScreen'
import todo from '../containers/todo/todo'
import addTodo from '../components/addTodoTask'
import SideBar from '../components/sideBar/sideBar'
import DashBoard from '../components/common/dashboardWidget'
import signUp from '../containers/signUp'
import editTodo from '../containers/todo/editTodo'
const authScreen = DrawerNavigator({
DashBoard: { screen : DashBoard },
Todo: { screen: todo }
},{
drawerPosition: 'left',
contentComponent: props => <SideBar {...props} />
},);
export const SignedOut = StackNavigator({
LoginScreen : {
screen : loginScreen,
navigationOptions : {
mode: "card",
title: "Sign in",
headerMode: "Screen",
header : null
}
},
signUp : { screen : signUp }
},{
headerMode: 'none'
},);
export const SignedIn = StackNavigator({
rootnavigator : { screen : authScreen },
addTodo : { screen : addTodo },
editTodo: { screen : editTodo }
},{
headerMode: 'none'
},);
export const createRootNavigator = (signedIn = false) => {
return StackNavigator(
{
SignedIn: {
screen: SignedIn,
navigationOptions: {
gesturesEnabled: false
}
},
SignedOut: {
screen: SignedOut,
navigationOptions: {
gesturesEnabled: false
}
}
},
{
headerMode: "none",
mode: "modal",
initialRouteName: signedIn ? "SignedIn" : "SignedOut"
}
);
};
and here is login button code
signIn() {
axios.post(BACKEND_URL+'/api/User/login', {
userName: this.state.userName,
password: this.state.password
})
.then( (response) => {
if(response.data.message == 'Success'){
// Set up root Auth Token and Headers
axios.defaults.headers.common['Authorization'] = "bearer "+response.data.data.accessToken;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
AsyncStorage.setItem('#userData:', JSON.stringify(response.data.data));
onSignIn().then(() => { this.props.navigation.navigate('SignedIn') });
this.setState({ isLoading: false });
}
})
.catch( (error) => {
alert("Please check your crendentials")
});
}
Instead of navigation.navigate try to navigation.dispatch to reset the routes to SignedIn StackNavigator. As,
Import NavigationActions from react-navigation. and use below code to dispatch your new route after user signedin.
onSignIn().then(() => { this.props.navigation.dispatch(
NavigationActions.reset({
index: 0,
key: null,
actions: [
NavigationActions.navigate({ routeName: 'SignedIn' })
]
})
)});
For more info read this Reset Navigation Action.

Replace old StackNavigator with a new one, React Native

I am trying to replace an StackNavigator that should not be used when the user has gone passed the "LogIn" stage. But i can't figure out how to do this, I have tried the reset function but can't get that to work as wanted.
How do I replace an old StackNavigator with a new and use that one? As shown in the example below the system starts with one stack and that stack should not be used after the button has been pressed.
the index code as an example:
import React, { Component } from 'react';
import { AppRegistry, Button, StyleSheet, Text, View } from 'react-native';
import { NavigationActions, StackNavigator } from 'react-navigation';
import App from './App';
class StackNavigatorStuff extends Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
return (
<View style={styles.container}>
<Text>
Welcome to this app
</Text>
<Text style={styles.instructions}>
Some login functions to become
</Text>
<Button title = 'Temp Login Function' onPress={() => /*Here should the stack be replaced with App.MainStackNav*/})}/>
</View>
);
}
}
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({routeName: 'Home'})
]
});
const StackNavigatorLab = StackNavigator({
Home: { screen: StackNavigatorStuff },
//More to be
});
AppRegistry.registerComponent('StackNavigatorLab', () => StackNavigatorLab);
And the App.MainStackNav
const StackNavigatorLab = StackNavigator({
Home: { screen: MainScreenNavigator },
Chat: { screen: ChatNavigator },
NavigationList: { screen: MyNotificationsScreen },
});
Navigation can only happen within a defined router, so you should have a navigator wrapping the screens you want to switch between.
In you index file's StackNavigatorLab, add App.MainStackNav to it as a route. i.e.
const StackNavigatorLab = StackNavigator({
Home: { screen: StackNavigatorStuff },
Main: { screen: App.MainStackNav },
...
});
And then your reset action would look like
const resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Main' })
]
});
Use navigation.dispatch to dispatch this reset action after successful login.
If you want to separate two sets of StackNavigation screens, you can have an overall StackNavigator as a root that just wraps the Login set of screens and the Main set of screen.