I had to refactor recently the navigation inside my React Native App using React Navigation.
Indeed, I have several navigators inside my app for different purposes: screens when not connected, screens when connected and some screens that should be available in both situations
(e.g. terms of use).
So my question is the following, if I have this pattern, how can I for example navigate from TermsOfUse to Register without going back to Welcome?
I can't use navigate.goBack() or navigation.navigate('Register') since those screens are not in the same StackNavigator, and duplicate the TermsOfUse in both navigators would be quite dirty.
// Screens
const NotConnectedScreens = {
Welcome: { screen: WelcomeScreen },
Register: { screen: RegisterScreen },
}
const ConnectedScreens = {
Homepage: { screen: HomepageScreen },
Tutorial: { screen: TutorialScreen },
}
const OthersScreens = {
TermsOfUse: { screen: TermsOfUseScreen },
}
// Stacks
const NotConnectedStack = createStackNavigator(NotConnectedScreens, {
initialRouteName: 'Welcome',
})
const ConnectedScreens = createStackNavigator(ConnectedScreens, {
initialRouteName: 'Homepage',
})
const OtherStack = createStackNavigator(OtherScreens, {
initialRouteName: 'TermsOfUse',
})
// App navigation
const AppContainer = createAppContainer(
createSwitchNavigator(
{
NotConnectedStack: NotConnectedStack,
ConnectedStack: ConnectedStack,
OthersStack: OthersStack,
},
{
initialRouteName: 'LandingStack',
defaultNavigationOptions: {
header: null,
headerMode: 'none',
},
}
)
)
export { AppContainer as default }
I can't use navigate.goBack() or navigation.navigate('Register') since
those screens are not in the same StackNavigator.
Not completely true, if your screen has a unique name, wherever you need to navigate to that page you can call the function this.props.navigation.navigate('SecondPage').
but sometimes going to an screen from another stack can't be done because it needs some data to be passed when navigating to. in this case MAKE SURE YOUR SCREEN HAS A DIFFERENT NAME
DevicesList: {screen: DevicesList },// this is wrong
DevicesListPage: {screen: DevicesList },// this is right
then you can navigate to that page like below from another stack:
this.props.navigation.navigate('DevicesListPage', {
//your data
});
Related
I am having an issue when I navigate from Home component that contains a list of companies and I press in a button to load the Company view, the data is being loaded but when I press back in Android is returning to Home and when I press in a different company button to load its details, is rendering the same view with the same previous data, that means, the component is not being updated/unmounted.
These are my routes
const drawerConfig = {
initialRouteName: 'Home',
contentComponent: SideMenu,
drawerWidth: width,
}
const MainDrawerNavigator = createDrawerNavigator(
{
Home: {
screen: Home,
},
Company: {
screen: Company,
},
Gifts: {
screen: Gifts,
},
Contact: {
screen: Contact
}
},
drawerConfig,
);
const InitialStack = createStackNavigator(
{
Menu: {
screen: Menu,
path: 'menu/',
}
},
{
initialRouteName: 'Menu',
headerMode: 'none',
}
);
const SwitchNavigator = createSwitchNavigator(
{
Init: InitialStack,
App: MainDrawerNavigator,
},
{
initialRouteName: 'Init',
}
);
const AppContainer = createAppContainer(SwitchNavigator);
export default AppContainer;
I am navigating from Home to Company with this
goToCompany = company => event => {
this.props.navigation.navigate('Company', {
company,
});
}
And receiving the params in Company with this
componentWillMount() {
this.setState({ companyData: this.props.navigation.getParam('company', {}) });
}
So I am expecting the Company component will unmount on pop or allow me to change the state of the Company component when I send the details from Home.
I am using react-navigation 3.5.1 and react-native 0.59.3
React native navigation does not work as web. Read here for more details. https://reactnavigation.org/docs/en/navigation-lifecycle.html
When you navigat to other screen it doesn't actually get unmounted. Read documentation for details.
Use willFocus instead.
you can try using componentDidUpdate check in docs
componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
You need to use the push method of navigation object. The push replace the current route with a new and the navigate search a route and if not exist create new one.
I'm working on a RN app, and when a user signs out of the app I reset all the Redux state to it's initial values and navigate to the Login screen. However, on signing back in, the navigation state has been carried over, which is causing problems. How can I reset the navigation state, so each sign in acts like a completely new app session?
My navigation looks like this:
const MainNavigator = createBottomTabNavigator(
{
login: { screen: Login },
main: {
screen: createBottomTabNavigator(
{
home: {
screen: createStackNavigator({
...
}),
},
map: {
screen: createStackNavigator({
...
}),
},
},
),
},
},
{
initialRouteName: 'login',
},
);
Many thanks!
from the api https://reactnavigation.org/docs/en/navigation-prop.html#dismiss
Call dismiss if you're in a nested (child) stack and want to dismiss the entire stack, returning to the parent stack.
So, use that
this.props.navigation.dismiss()
I am using react-native-navigation and trying to create a DrawerNavigator which does not unmount the previously opened screens just like how TabNavigator works. Because one of my screens contains a webview and I do not want it to reload everytime I change screens.
Here is some sample code in App.js..
const Drawer = DrawerNavigator(
{
Home: { screen: Home },
PageWithWebview: { screen: PageWithWebview},
Settings: { screen: Settings },
},
{
initialRouteName: "Home",
contentComponent: props => <SideBar user={global.user} />
}
);
const AppNavigator = StackNavigator(
{
Drawer: { screen: Drawer },
},
{
initialRouteName: "Drawer",
headerMode: "none"
}
);
export default () =>
<Root>
<AppNavigator/>
</Root>;
And in my Sidebar component I have buttons to navigate to a different route depending on what is selected .
onPress={() => this.props.navigation.navigate(selected, { userDetails: global.user })}
In the later versions of react native navigation they added the unmountInactiveScreens property for the DrawerNavigator
unmountInactiveScreens
Whether a screen should be unmounted when navigating away from it. Unmounting a screen resets any local state in the screen as well as state of nested navigators in the screen. Defaults to false.
I have a react-native application whose top level App.js is as follows:
const AuthStack = createStackNavigator(
{ Landing, SignUpWithGoogle },
{
initialRouteName : 'Landing'
, navigationOptions : {
header : null
}
}
);
const AppStack = createStackNavigator(
{
AppContainer
, Campaign
, Compose
},
{
initialRouteName : 'AppContainer'
, navigationOptions : {
header : null
}
}
);
/**
#TODO:
force app to reload on user creation ...
there needs to be a state transition on user creation
... not sure how to
*/
class App extends React.Component {
render () {
const stack = (!this.props.authenticating && this.props.user)
? <AppStack {...this.props} />
: <AuthStack />
return (
<Loader
isLoaded = { !this.props.authenticating && this.props.feedIsLoaded}
imageSource = {logo}
backgroundStyle = {loading.loadingBackgroundStyle}
>
{stack}
</Loader>
)
}
}
There is a Loader component from https://github.com/TheSavior/react-native-mask-loader that hides the app with a splash page until the app has fetched user authentication data, or determined that this is a new user. This works great except in the case when the user signs up for the first time, then the app just jumps right into authenticated mode, and fails to load initial data that I want for the new user. The only to get around this is to restart the app, which is a no go. Is there a way to transition between AuthStack and AppStack better so that the information I want on signup are all there? One way would be to force reload the app so that we are directed back to the Loader screen and state, but it's unclear how this can be done.
I did something like this for my use case.
const Routes = {
Login: {
screen: Login
},
Status: {
screen: Status,
navigationOptions: {
gesturesEnabled: false, // To prevent swipeback
},
},
...
};
const LoggedRootStack = createStackNavigator(
{
...Routes
},
{
initialRouteName: 'Status'
}
)
const RootStack = createStackNavigator(
{
...Routes
},
{
initialRouteName: 'Login'
}
)
For passing props use Redux for keeping a global state. You can connect your components to redux state to access the props. Hope this helps
I am using TabNavigator from react-navigation. It's working fine but I need to do a little trick.
When I navigate between StackNavigator routes, after changing tabs I need my route go directly in the initial route. So I need the route state to be reset.
const HomeStack = StackNavigator({
Main: { screen: HomeScreen },
Profile: { screen: ProfileScreen },
});
const AboutStack = StackNavigator({
Main: { screen: AboutScreen },
});
TabNavigator(
{
Home: { screen: HomeStack },
About: { screen: AboutStack },
}
Let's say I am in the Main route from the Home tab and then I have navigated to Profile before switching to the About tab. When I go back to the Home tab I want my app directly to navigate to the Main route and clear history. Just like a reset.
Any suggestion ?
You maybe could use the willFocus listener in the Profile route of your HomeStack.
Listener:
class Profile extends Component {
componentDidMount() {
this.didFocusListener = this.props.navigation.addListener(
'didFocus',
() => { console.log('did focus') },
);
}
componentWillUnmount() {
this.didFocusListener.remove();
}
render() {
return ( /* your render */ );
}
}
And then in the case you are on Main and you are navigating to your Profile route. You should set a params in the navigation to say that the previous route is Main.
Route parameters: navigation.navigate('Profile', { previous_screen: 'Main' });
So now in your willFocus listener:
if the previous_screen param is set, it means that you don"t have to do anything.
If not, means that you come from the other tab and that it will navigate to the wrong route. So you can either reset you're navigation route or just navigate to the 'Profile' route.
NOTE:
I didn't try this solution and maybe the transition animation is not going to be smooth. So tell me if it does the job well or not.