re render navigator screen in react navigation - react-native

Hi I am using React Navigation (v:6) in my React Native app for navigation. I have a StackNavigator like the following.
const AppStackNavigator = createStackNavigator<AppStackParamList>();
export const AppStack = () => {
const loggedIn = useSelector((state: AppState) => state.auth?.data?.accessToken ?? null);
return (
<AppStackNavigator.Navigator headerMode="none" mode="modal">
{loggedIn && (
<AppStackNavigator.Screen name={routes.OnboardingStack.MAIN_TABS} component={MainTabs} />
)}
<AppStackNavigator.Screen name={routes.appStack.MainStack} component={MainStack} />
};
I am trying to have the MainTabs when the user has logged in. But when the user has logged in and navigated to the Home screen which is in the MainStack I don't see the MainTabs at the bottom. But If I reload the app from the debugger menu, I can see the MainTabs at the bottom of the screen.
I think React Navigation is using some sort of optimization to prevent re-render, Is there a way to forcefully re-render a stack in react navigation? Or any other solution?

Related

Navigating to screen in another navigator in React Navigation 5

I'm using the new React Navigation 5 in my React Native app.
The main menu is handled by the RootNavigator which is a Drawer. The login/sign up are handled by AuthNavigation which is a Stack.
I'm trying to send user to Home screen under RootNavigator after a successful login. In other words, I'm trying to send user to a screen under another navigator by issuing navigation.navigate('RootNavigator', {screen: 'Home'}); but I'm getting an error that reads:
The action 'NAVIGATE' with payload {"name":"RootNavigator"} was not
handled by any navigator.
Do you have a screen named 'RootNavigator'?
This is what my App.js looks like:
const App = () => {
const [isLoading, setIsLoading] = useState(true);
const [isAuthenticatedUser, setIsAuthenticatedUser] = useState(false);
useEffect( () => {
// Check for valid auth_token here
// If we have valid token, isLoading is set to FALSE and isAuthenticatedUser is set to TRUE
});
return (
<Provider store={store}>
<PaperProvider>
<NavigationContainer>
{
isLoading
? <SplashScreen />
: isAuthenticatedUser ? <RootNavigator /> : <AuthNavigator />
}
</NavigationContainer>
</PaperProvider>
</Provider>
);
};
And here's my AuthNavigator which is a Stack:
import React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
// Components
import Login from '../../login/Login';
const AuthStack = new createStackNavigator();
export const AuthNavigator = () => {
return(
<AuthStack.Navigator>
<AuthStack.Screen name="LoginScreen" component={Login} />
</AuthStack.Navigator>
);
};
And here's the RootNavigator which is a Drawer:
import React from 'react';
import { createDrawerNavigator } from '#react-navigation/drawer';
// Components
import Dashboard from '../../home/Dashboard';
import DrawerContent from './DrawerContent';
import ToDoList from '../../active_lists/to_do_lists/ToDoList';
const MainMenuDrawer = createDrawerNavigator();
export const RootNavigator = () => {
return (
<MainMenuDrawer.Navigator drawerContent={(navigation) => <DrawerContent navigation={navigation} />}>
<MainMenuDrawer.Screen name="Home" component={Dashboard} />
<MainMenuDrawer.Screen name="To Do List" component={ToDoList} />
</MainMenuDrawer.Navigator>
);
};
Any idea what I'm doing wrong here? I want to use the cleanest approach for handling this.
There are 2 issues:
You're doing navigation.navigate('RootNavigator', {screen: 'Home'});, which means navigate to Home screen in a navigator nested inside RootNavigator screen. but there's no screen named RootNavigator, you have a component named RootNavigator, but navigate expects a screen name.
Looking at your code, you don't have nested navigators, both navigators are still at the root, just rendered conditionally. So you'd usually do navigation.navigate('Home') for navigation.
Examples of how nesting works and how the structure looks when you nest: https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator
When you are conditionally defining screens/navigators, React Navigation will take care of rendering correct screens automatically after you change the condition. You don't do navigate in this case.
From the auth flow docs:
It's important to note that when using such a setup, you don't need to navigate to the Home screen manually by calling navigation.navigate('Home'). React Navigation will automatically navigate to the Home screen when isSignedIn becomes true.
Auth flow docs: https://reactnavigation.org/docs/auth-flow#how-it-will-work
So what you need to do, is change the isAuthenticatedUser state in your component. You can follow the guide in the docs for an example using React context, but if you're using Redux, move this state to Redux, or any other state management library you use.
And lastly, remove the navigation.navigate after successful login, since it'll happen automatically when you update your condition.

Open drawer navigation from tab navigation tab

I'm using a tab navigator and drawer navigator in a react native app. I need to have the drawer navigator open when one of the tabs is pressed. For example, the last tab named 'account' should open up the drawer.
// drawer navigation
const AppDrawerNavigator = createDrawerNavigator({
Account: AccountScreen,
});
// tab navigation
const AppTabNavigator = createBottomTabNavigator({
Home: {
screen: HomeScreen,
},
Account: {
screen: AppDrawerNavigator,
}
});
With my code right now, the app is simply navigating to the account screen when the account tab is pressed, instead of opening up the drawer. Is there a way to do this?
I found my answer on this question > React Native - Accessing drawer navigation outside of AppNavigator
I created a NavigationService and added the following to the service.
function openDrawer(routeName, params) {
_navigator.dispatch(DrawerActions.openDrawer());
}

Stack navigator not working inside drawer navigator in react native

I am making an react native android app in which i have both stack navigator and drawer navigator like this.
const orderstack = createStackNavigator({
OrderHistory : {screen : OrderHistory},
HistoryDetails: {screen : HistoryDetails},
TrackOrder: {screen : TrackOrder},
},{
headerMode: 'none',
navigationOptions:({navigation}) => ({
header: null,
}),
})
and drawer is
const drawerNavigator = createDrawerNavigator({
HomeScreen: {
screen: orderstack,
},
ProfileScreen:{
screen: profile,
},
MOrderScreen: {
screen: customstack,
},{}
}
Now when i go to HomeScreen in drawer then it should open orderstack which is stack navigator.This is working fine until i am not in the HomeScreen inside drawer,i mean,suppose i am inside HomeScreen and inside that i am in HistoryDetails then when i press again HomeScreen in drawer then it does not goes in OrderHistory.I tried setting initialRoutename but it does not works?But if i click from MOrderScreen or ProfileScreen then its working fine and OrderHistory is opening first.
The drawer only knows that it has to navigate to the "orderstack" screen, in this case, is a stacknavigator, but when you are in HistoryDetails or TrackOrder , you are still in the "orderstack" screen , the drawer doesn't handle deep navigation. It only navigates between the screens that you have provided it. you need to define a custom contentcomponent to handle navigation in your way. This behaviour of going back to the initial screen is already present in tabnavigator of react anvigation 3.0 so you should try it out to see if it fits your needs.
Check here for how to implement a customcomponent that resets the stack navigator , or just use a tabnavigator wich is the recommended for reseting screens (that's how youtube app does it)

react navigation splash screen to login screen

I have created a splash screen and a login screen. I would like that after 2 second my screen goes splash to log in but it's showing: undefined is not an object(evaluating
'_this.props.navigation.push ')
In this project I am using react-navigation
componentWillMount(){
setTimeout(
() => {
this.props.navigation.push({
screen:'smartbill.login',
title:'LOGIN SCREEN'
});
}
, 1000);
}
Hope you have created a stack navigator
const App = createStackNavigator({
Splash: { screen: SplashScreen },
Login: { screen: LoginScreen },
});
In Splash Screen
setTimeout(()=> {
navigate('Login', { name: 'Jane' })
},1000);
Below is an example of me navigating to a home screen from splash
setTimeout(
()=> {
this.props.navigation.navigate("Home");
},1000
);
For Navigation you should use StackNavigator in react-native thats the proper method
Where did you get this this.props.navigation.push thats not proper.
Or
I have an excepted answer in the below question.
How to navigate from splash screen to login screen in react native?
There is a google drive link on it from where you can download a sample project, its a simple app figure it out from the sample app how you should set up the App.js.
I suggest You should use StackNavigator for navigation its the best method to follow in my app App.js is configured using StackNavigator.

How to invoke App.js from inner component ReactNative?

I'm using StackNavigator to load a Tabbar created with react-native-tab-navigator in App.js. I have a view inside Tabbar. How can I navigate back to App.js from that view?
App.js
import { StackNavigator } from 'react-navigation';
const SigninSignup = StackNavigator({
Signup: { screen: Signup },
Signin: { screen: Signin },
});
render() {
if (this.state.condition) {
return (<Tabbar />);
} else {
return (<SigninSignup />);
}
}
Myview.js (It is inside Tabbar)
How can I go back to App.js and load SigninSignup ?
I have tried
const { navigate } = this.props.navigation;
navigate('Signin', {});
But getting ERROR undefined is not an object (evaluating 'this.props.navigation')
Your navigation hierarchy starts with the SigninSignup navigator.
Since your component is rendering either the navigator or your tab bar according to this.state.condition, you can't just navigate to the other screen.
You con solve this be either moving the tab bar and the SigninSignup navigator into a new root navigator and use that to navigate between everything, or by providing a function to Tabbar that would change the value of condition:
<Tabbar onSomething={() => this.setState({condition: !this.state.condition})} />