react native navigation between screens - react-native

I'm trying to use reactnavigation.org library and I have some issue with that. I have two types of navigation screens. Two screens are a registration and authorization. And others are regular app screens. Problem is that I can't render parent component App.js or other functionality to reload app from child component and thus change my screens block. Navigation between screens Run, History, Profile, OtherRunners works fine. Navigation between screens Main and Enter works fine. But if I need navigate from Run to Main, or from Enter to Run there is a problem.
App.js
const App = () => {
const Stack = createStackNavigator()
const Drawer = createDrawerNavigator()
const [loggedIn, setLoggedIn] = useState(false)
async function getUserEmail(){
if(await AsyncStorage.getItem('#email')){
setLoggedIn(true)
}else{
setLoggedIn(false)
}
}
getUserEmail()
function MenuDraw(){
return(
<Drawer.Navigator
drawerContentOptions={}
drawerType={}
drawerStyle={{}}
>
<Drawer.Screen
name="Run"
component={Run}
options={}
/>
<Drawer.Screen
name="History"
component={History}
options={}
/>
<Drawer.Screen
name="Profile"
component={Profile}
options={}
/>
<Drawer.Screen
name="OtherRunners"
component={OtherRunners}
options={}
/>
<Drawer.Screen
name="LogOut"
component={Run}
initialParams={{action: 'logout'}}
options={}
/>
</Drawer.Navigator>
)
}
function MyDrawer(){
if(loggedIn){
return(
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"MenuDraw"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw}/>
<Stack.Screen name="Details" component={Details}/>
</Stack.Navigator>
)
}else{
return (
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"Main"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw} />
<Stack.Screen name="Details" component={Details} />
<Stack.Screen name="Main" component={Main} />
<Stack.Screen name="Enter" component={Enter} />
</Stack.Navigator>
)
}
}
return(
<NavigationContainer>
<MyDrawer/>
</NavigationContainer>
)
}
export default App;
I tried using reload app tools, but those wasn't help me. They are wasn't working. In this section of code which is below. On the Run screen.
Run.js
const Run = ({navigation,route}) => {
const clearStorage = async () => {
await AsyncStorage.clear()
}
if(route.params){
if(route.params.action === 'logout'){
clearStorage()
navigation.navigate("Main", {})
}
}
}
export default Run;
I'm trying to logout by cleaning the storage and navigate to Main screen. But it's not working on release mode. I've tried this, which is below.
App.js
function MyDrawer(){
if(loggedIn){
return(
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"MenuDraw"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw}/>
<Stack.Screen name="Details" component={Details}/>
++++ <Stack.Screen name="Main" component={Main} />
++++ <Stack.Screen name="Enter" component={Enter} />
</Stack.Navigator>
)
}else{
return (
<Stack.Navigator
screenOptions={{headerShown: false}}
initialRouteName={"Main"}
>
<Stack.Screen name="MenuDraw" component={MenuDraw} />
<Stack.Screen name="Details" component={Details} />
<Stack.Screen name="Main" component={Main} />
<Stack.Screen name="Enter" component={Enter} />
</Stack.Navigator>
)
}
}
Not working either way. How can I fix it? Can I render App.js component from child screens? Or perhaps I should create two screen blocks line
<Stack.Screen name="MenuDraw" component={MenuDraw}/>
<Stack.Screen name="MenuRegister" component={MenuRegister}/>
and put all my screens by belongings to match section?
I need to logout from this section:
App.js
some code
<Drawer.Screen
name="LogOut"
component={Run}
initialParams={{action: 'logout'}}
options={}
/>
</Drawer.Navigator>
some code

Did you try using useEffect hook, to get on the road? :-)
useEffect(() => {
const getUserEmail = async () => {
if(await AsyncStorage.getItem('#email')){
setLoggedIn(true)
}else{
setLoggedIn(false)
}
};
getUserEmail();
}, []);

Related

React Navigation - Drawer inside Stack go back

Taking this example for the official documentation :
function Root() {
return (
<Drawer.Navigator>
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Drawer.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Root"
component={Root}
options={{ headerShown: false }}
/>
<Stack.Screen name="Feed" component={Feed} />
</Stack.Navigator>
</NavigationContainer>
);
}
They just explain here how to navigate to the Profile screen from the Feed screen like this :
navigation.navigate('Root', { screen: 'Profile' });
I would to know how can I navigate to the Feed screen from the Profile screen;
You can just use the navigation object and its navigate function since the Feed screen is nested inside the same navigator as the Root stack.
Destructure the navigation object from the props of Profile.
function Profile({navigation}) {
return ...
}
Now, just use the navigation object as follows in order to navigate to Feed.
navigation.navigate("Feed")

"Tried to Synchronously call anonymous function from a different thread."

I have this issue whenever I toggle the drawer on my screen. I want to login and then go to Home page where there will be a drawer. But I don't know where the issue is.
PS: I have Expo managed project and I already installed react-native-gesture-handler and react-native-reanimated.
This is the code for navigating :
const Stack = createNativeStackNavigator();
const Drawer = createDrawerNavigator();
const DrawerComponent = () => {
return (
<Drawer.Navigator>
<Drawer.Screen name="Dashboard" component={Test} />
<Drawer.Screen name="Reset" component={Reset} />
</Drawer.Navigator>
);
};
const Navigation = () => {
return (
<Stack.Navigator>
<Stack.Screen name="StartUp" component={StartUp} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="Register" component={Register} />
<Stack.Screen name="Reset" component={Reset} />
<Stack.Screen name="DrawerComponent" component={DrawerComponent} options={{title: "drawer"}}/>
</Stack.Navigator>
);
};
export default Navigation;

How to decide which component should be rendered dynamically in React Navigation?

This is my structure:
const RootStack = () => (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeTabs} />
<Stack.Screen name="AddNote" component={AddNoteScreen} />
</Stack.Navigator>
);
const HomeTabs = () => (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeStack}/>
<Tab.Screen name="Customers" component={CustomersStack}/>
</Tab.Navigator>
);
const HomeStack = () => (
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen}/>
<Stack.Screen name="Tickets" component={TicketsStack}/>
</Stack.Navigator>
);
const CustomerStack = () => (
<Stack.Navigator>
<Stack.Screen name="Customer" component={CustomerScreen}/>
<Stack.Screen name="Tickets"
initialParams={{ parentRouteConfig: true }}
component={TicketsStack}
/>
</Stack.Navigator>
);
const TicketStack = (props) => {
const { route } = props;
const { params } = route;
return (
<Stack.Navigator>
<Stack.Screen
name={params?.parentRouteConfig ? 'CustomerTickets' : 'Tickets'}
component={params?.parentRouteConfig ? CustomerTicketsScreen : TicketsScren}
/>
<Stack.Screen name="TicketDetail" component={TicketDetailScreen} />
</Stack.Navigator>
);
};
The problem is: In ticket stack I need to decide which screen should I render. FYI: to navigate from drawer or any other higher navigator,
I needed to give different name to Screen. Current implementation solves the problem that I have. But it smells, I know that
there is a better solution for this but I can't find it. What is the best practice to achieve this? Instead of initialParams can I use different technique?
Based on react-navigation documentation, I'm doing the following for all my "conditional screen".
<Stack.Navigator>
{params?.yourConditionVariable ? (
<Stack.Screen
name="CustomerTickets"
component={CustomerTicketsScreen}
/>
) : (
<Stack.Screen name="Tickets" component={TicketsScreen} />
)}
</Stack.Navigator>
It works pretty well, and it's the biggest feature of RN v5 on my side. I really love this flexibility!

React Native: Different headers for different screens in Stack Navigator

I am using #react-navigation/stack version ^5.5.1. I am trying to have different headers on different screens in my Stack Navigation. For example, on Master, I want no header, i.e., headerMode="none"; on Home, I want a custom header, and on Details I want a different custom header. How do I achieve this? This is my current code:
const AppStack = () => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Master" component={ Master } />
<Stack.Screen name="Home" component={ Home } />
<Stack.Screen name="Details" component={ Details } />
</Stack.Navigator>
</NavigationContainer>
)
}
I just figured it out.
First, put headerMode="screen" on the Stack.Navigator. This moves control of the header to each screen. Then use the syntax as shown below for each individual screen.
const AppStack = () => {
return (
<NavigationContainer>
<Stack.Navigator headerMode="screen">
<Stack.Screen name="Master" component={ Master } options={{ headerShown: false }} />
<Stack.Screen name="Home" component={ Home } options={{ headerTitle: props => <MyCustomHeader {...props} /> }}/>
<Stack.Screen name="Details" component={ Details } options={{ headerTitle: props => <MyOtherCustomHeader {...props} /> }}/>
</Stack.Navigator>
</NavigationContainer>
)
}

React Navigation: How to Display Navigation Drawer in all screens?

I have a Navigation Drawer which should appear in all my screen(Except for the Splash screen).
I've got it that way:
const Stack = createStackNavigator();
const Drawer = createDrawerNavigator();
const StackNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name="EstateDetails" component={Screens.EstateDetails} />
<Stack.Screen name="Tour" component={Screens.Tour} />
<Stack.Screen name="Comparison" component={Screens.Comparison} />
<Stack.Screen name="Blog" component={Screens.Blog} />
<Stack.Screen name="Auth" component={Screens.Auth} />
</Stack.Navigator>
);
};
const DrawerNavigator = () => {
return (
<Drawer.Navigator drawerContent={props => CustomDrawerContent(props)}>
<Drawer.Screen name="HomeScreen" component={Screens.Home} />
<Drawer.Screen name="stack" component={StackNavigator} />
<Drawer.Screen name="RegisterEstate" component={Screens.RegisterEstate} />
<Drawer.Screen name="Filter" component={Screens.Filter} />
<Drawer.Screen name="Conditions" component={Screens.Conditions} />
<Drawer.Screen name="Judicial" component={Screens.Judicial} />
<Drawer.Screen name="ContactUs" component={Screens.ContactUs} />
<Drawer.Screen name="ReportBugs" component={Screens.ReportBugs} />
</Drawer.Navigator>
)
};
export const AppNavigator = () => {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Splash">
<Stack.Screen name="Splash" component={Screens.Splash}/>
<Stack.Screen name="Home" component={DrawerNavigator}/>
</Stack.Navigator>
</NavigationContainer>
);
};
In this case, all the okay only stack screens act as drawer screen.
(The screen only loads once and shows the initial load next time, like blog screens).
‌
I need to have the cursor on all pages except splash and to stack some of my pages (like dynamic pages that don't have the same content)
If you want to display same drawer in all other screens just pass {DrawerNavigator} to all other screens where you want to show the Drawer.So in your example if you want to show Drawer in Tour and Blog screen just add
<Stack.Screen name="Blog " component={DrawerNavigator} />
<Stack.Screen name="Tour" component={DrawerNavigator} />
Now you can access in Blog and Tour screen.
If you want to show a different Drawer in other screens then Create a new function.