Can't navigate to another screen - react-native

I am having a bit of trouble with react-navigation
import React, {useState,useEffect} from 'react';
import {Image} from "react-native";
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import Home from "./src/screens/Home.js";
import InvitePage from './src/screens/InvitePage.js';
import WelcomePage from './src/screens/WelcomePage.js';
import NamePage from './src/screens/NamePage.js';
import AsyncStorage from '#react-native-async-storage/async-storage';
const Stack = createStackNavigator();
function LogoTitle() {
return (
<Image
style={{ width: 50, height: 50 }}
source={require("./assets/Appicon.png")}
/>
);
}
function App() {
const [userName,setuserName]=useState(null);
const [loading, setLoading] = useState(true)
useEffect(() => {
async function getName(){
try {
const result= await AsyncStorage.getItem('namekey')
setuserName(result);
setLoading(false);
}
catch(e) {
setLoading(false);
}
}
getName();
}, []);
if (loading) {
return (
<></>
)
}
return (
<NavigationContainer>
<Stack.Navigator>
{userName ?
(<Stack.Screen name="Home" component={Home}
options={{
headerTitle: props => <LogoTitle {...props} /> ,
headerStyle: {
height: 120,
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}/>):(
<>
<Stack.Screen name="WelcomePage" component={WelcomePage}
options={{
title: 'Welcome',
headerStyle: {backgroundColor:'#fff',height: 100 },
}}
/>
<Stack.Screen name="NamePage" component={NamePage}
options={{
title: 'Welcome',
headerStyle: {backgroundColor:'#fff',height: 100 },
}}
/>
</>
)}
<Stack.Screen name="InvitePage" component={InvitePage}
options={{
title: 'Invite',
headerStyle: {backgroundColor:'#fff',height: 100 },
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
This is my app.js.Here, I am reading a file using async storage and then i decide based on that which screen i want to navigate to but the problem is when i go to my name setup page and after saving the name to async storage I can't navigate to home page for some reason
i am getting this error:
The action 'NAVIGATE' with payload {"name":"Home"} was not handled by any navigator.
Do you have a screen named 'Home'?
If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.
i think maybe home page is not getting initialized in this code?
This is my namePage:
async function next(){
try {
await AsyncStorage.setItem('namekey', name)
console.log("done")
} catch (e) {
console.log("errorNamePage")
}
navigation.navigate("Home");
}
return(
<View style={styles.headerview}>
<Text style={{fontSize:30,marginTop:250,fontFamily:"AzoSans-Medium",marginLeft:30,marginRight:30}}>Please enter your name</Text>
<TextInput
style={styles.input}
placeholder="Name"
onChangeText={name => setName(name)}
defaultValue={name}
onSubmitEditing={()=>next()}
autoCorrect = {false}
/>
<TouchableOpacity style={{marginTop: 150}} onPress={()=> next()}>
<Image source={require('../../assets/welcome-next.png')} style={{width:100, height: 100,marginLeft:150}} />
</TouchableOpacity>
</View>
);
};

The condition you used in navigator probably separates NamePage and Home, so they are not accessible for each other I guess. Once you get to Name page, userName must be a truthy value to navigate to Home
If you tell about your intention more, people here can show you a simpler solution.

Related

React-Native Header Title and Tab Navigator

I’ve a problem I cannot find an answer to, even though I’ve found similar problems with answers.
Basically, I pull a name (and other info) from a database. I then navigate to a screen (Screen A) in a tab navigator. I place the name into the header title of that screen (needed a stack navigator to do that I discovered from this site). I then have a second tab (Screen B) I can navigate to and want that same name placed in the header title there.
While on Screen B I also need to change the name and have that placed back into the header title of both Screen A and Screen B.
How do I do this? I have example code below that hopefully explains in more detail.
App.js
import React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { HomeScreen, ScreenA, ScreenB } from './ui/screens.js';
const AStack = createStackNavigator();
function ScreenAStack(headerProps) {
return (
<AStack.Navigator>
<AStack.Screen name="Screen A" component={ScreenA} />
</AStack.Navigator>
);
}
const BStack = createStackNavigator();
function ScreenBStack(headerProps) {
return (
<BStack.Navigator>
<BStack.Screen name="Screen B" component={ScreenB} />
</BStack.Navigator>
);
}
const BottomTab = createBottomTabNavigator();
function Tabs() {
return (
<BottomTab.Navigator
screenOptions={{ headerShown: false }}
>
<BottomTab.Screen name="Screen A Stack" options={{ title: "Screen A" }}>
{(props) => (
<ScreenAStack {...props} />
)}
</BottomTab.Screen>
<BottomTab.Screen name="Screen B Stack" options={{ title: "Screen B" }}>
{(props) => (
<ScreenBStack {...props} />
)}
</BottomTab.Screen>
</BottomTab.Navigator>
);
}
const Stack = createStackNavigator();
const App = () => {
return (
<NavigationContainer>{
<Stack.Navigator>
<>
<Stack.Screen name="Home Screen" options={() => ({ headerShown: true })} component={HomeScreen} />
<Stack.Screen name="Screen A Tabs" options={() => ({ headerShown: false })} component={Tabs} />
</>
</Stack.Navigator>
}</NavigationContainer>
);
}
export default App;
screens.js
import React, { useEffect } from 'react';
import { View, Text, TextInput, StyleSheet, Button, } from 'react-native';
export function HomeScreen({ navigation }) {
// Get name from server using api and send to Screen A.
navList = (item) => {
navigation.navigate("Screen A Tabs", {
screen: 'Screen A Stack',
params: {
screen: 'Screen A',
params: { item },
},
});
}
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen.</Text>
<Button title="Go to Tab Screen" onPress={() => navList({name: "Name here!"})} />
</View>
);
}
export function ScreenA({ route, navigation }) {
// Place name into header title.
useEffect(() => {
navigation.setOptions({
title: route.params.item.name,
});
}, [route]);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Screen A</Text>
</View>
);
}
export function ScreenB({ navigation }) {
// Update header title with new name and update name on server using api.
const [newName, setNewName] = React.useState("");
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Screen B</Text>
<TextInput
value={newName}
onChangeText={newName => setNewName(newName)}
placeholder="Type new name here."
/>
<Button title="Change Name" onPress={() => console.log("Change name to " + newName)} />
</View>
);
}
I will give a short answer. your do not need to create a separate stacks for a single screen. here you can create a simple bottom tab navigator. just a sample.
<Tab.Navigator
initialRouteName="SearchScreen"
backBehavior="initialRoute"
screenOptions={{headerShown: false}}
>
<Tab.Screen
name="SearchScreen"
component={SearchScreen}
options={{
headerShown: false,
tabBarLabel: 'Search',
tabBarIcon: 'search',
}}
/>
<Tab.Screen
name="DialerScreen"
component={DialerScreen}
options={{
headerShown: false,
tabBarLabel: 'Dialer',
tabBarIcon: 'dialer',
}}
/>
</Tab.Navigator>
after this create a simple stack and add this bottom or top tab navigator like this
<Stack.Screen
name="Home"
component={TopTabNavigator}
options={{headerShown:true}}
/>
you can change title like this
onPress={() => {
if (item.is_analog) {
navigation.setOptions({title: 'Analog Speedo Meter'});
} else {
navigation.setOptions({title: 'Digital Speedo Meter'});
}
}}
cheers

React Navigation Nested No Route Params v5

I can't seem to get any route params in my nested navigator. The params are present in the parent navigator, but they are not reachable in the child navigator.
So the child navigator does render the correct screen, but it does not have any params in the route (namely a category or product id).
It feels like I am misusing some syntax, but I can't quite figure out which one. Here is the stack of code, edited down a bit to make it easier to read.
Snack on Expo
Thank you.
Note: These are separate files so the includes are off.
import * as React from 'react';
import { Text, View, StyleSheet, SafeAreaView } from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { NavigationContainer } from '#react-navigation/native'
import { createDrawerNavigator, DrawerContentScrollView, DrawerItem } from '#react-navigation/drawer'
import { createStackNavigator } from '#react-navigation/stack'
import { AppearanceProvider } from 'react-native-appearance'
const Drawer = createDrawerNavigator()
const Stack = createStackNavigator()
const HomeScreen = ({ navigation, route }) => {
return(
<View style={styles.container}>
<Text>Home Screen </Text>
</View>
)
}
const CategoryScreen = ({ navigation, route }) => {
return(
<View>
<Text>Category Screen </Text>
<Text>{JSON.stringify(route)}</Text>
</View>
)
}
const ProductScreen = ({ navigation, route }) => {
return(
<View>
<Text>Product Screen </Text>
<Text>{JSON.stringify(route)}</Text>
</View>
)
}
const CustomDrawerContent = ({ props }) => {
return (
<DrawerContentScrollView {...props}>
<DrawerItem
label="Home"
onPress={() => props.navigation.navigate('Home')}
/>
<DrawerItem
label="Category 1"
onPress={() =>
props.navigation.navigate('Main', {
Screen: 'Category',
params: { id: 1 },
})
}
/>
<DrawerItem
label="Category 2"
onPress={() =>
props.navigation.navigate('Main', {
Screen: 'Category',
params: { id: 101 },
})
}
/>
</DrawerContentScrollView>
)
}
const MainNavigator = () => {
return (
<Stack.Navigator>
<Stack.Screen name="Category" component={CategoryScreen} />
<Stack.Screen name="Product" component={ProductScreen} />
</Stack.Navigator>
)
}
const ApplicationNavigator = () => {
return (
<NavigationContainer initialRouteName="Home">
<Drawer.Navigator
drawerContent={(props) => {
return <CustomDrawerContent props={props} />
}}
>
<Drawer.Screen
name="Home"
component={HomeScreen}
/>
<Drawer.Screen
name="Main"
component={MainNavigator}
/>
</Drawer.Navigator>
</NavigationContainer>
)
}
export default function App() {
return <ApplicationNavigator />
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
padding: 8,
backgroundColor: '#FFFFFF',
},
});
UPDATE
I have noted that if I initialize the params (blank, with values, whichever) outside of the custom drawer content first, the above code begins to work as expected.
Very simple and silly fix that a rubber duck could solve.
Screen !== screen. I was passing in an unknown param to navigate.

React Native: Deep linking doesn't work properly with StackNavigator

I am trying deeplinking in React-Native. The code works properly when the app is in the background. But once I remove the app from background and try to launch it using the link in safari. The app is launched with details screen. But I could not find previous (Home) screens in the Navigation Stack. Please find the code below:
/* eslint-disable react-native/no-inline-styles */
import 'react-native-gesture-handler';
import React from 'react';
import {TouchableOpacity, Text, View} from 'react-native';
import {useLinking, NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
const HomeScreen = ({navigation}) => {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text>Home Screen</Text>
<TouchableOpacity
onPress={() => {
navigation.navigate('Details', {itemId: 40});
}}>
<Text>Go to Details</Text>
</TouchableOpacity>
</View>
);
};
const DetailScreen = ({route, navigation}) => {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
<Text>Details Screen</Text>
<Text>Item Id: {route.params.itemId}</Text>
<TouchableOpacity onPress={() => navigation.goBack()}>
<Text>Go Back</Text>
</TouchableOpacity>
</View>
);
};
const Stack = createStackNavigator();
const App = () => {
const ref = React.useRef();
const {getInitialState} = useLinking(ref, {
prefixes: ['deeplink://'],
config: {
initialRouteName: 'Home',
Home: 'Home',
Details: {
path: 'Details/:itemId',
parse: {
itemId: null,
},
},
},
getPathFromState(state, config) {
console.log(state);
},
});
const [isReady, setIsReady] = React.useState(false);
const [initialState, setInitialState] = React.useState();
React.useEffect(() => {
Promise.race([
getInitialState(),
new Promise((resolve) => setTimeout(resolve, 150)),
])
.catch((e) => {
console.error(e);
})
.then((state) => {
if (state !== undefined) {
setInitialState(state);
}
setIsReady(true);
});
}, [getInitialState]);
if (!isReady) {
return null;
}
return (
<NavigationContainer
fallback={<Text>Loading...</Text>}
initialState={initialState}
ref={ref}>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
Launched the app using "deeplink://Details/86" in Safari.
First, update to latest version of #react-navigation/native and then follow the linking docs: https://reactnavigation.org/docs/configuring-links/
Instead of useLinking, you can pass a linking prop to the NavigationContainer component. Then change your config to following:
const App = () => {
const linking = {
prefixes: ["deeplink://"],
config: {
initialRouteName: "Home",
screens: {
Home: {
path: "home",
},
Details: {
path: "details/:itemId"
}
}
}
};
return (
<NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailScreen} />
</Stack.Navigator>
</NavigationContainer>
);
};
Then you can open links like deeplink://home or deeplink://details/someid.

How to remove the back button in the header react native

I want to remove the button back, but leave the header.
My component is as follows. I want to leave the title, and I don’t need the back button.
import React from 'react';
import { View } from 'react-native';
export const TrucksScreen = () => {
return (
<View>
....
</View>
);
});
TrucksScreen.navigationOptions = {
headerTitle: 'Trucks Screen',
};
How can I remove the button back?
Using headerLeft: null will be deprecated in future versions.
Instead use a function like so :
TrucksScreen.navigationOptions = {
headerTitle: 'Trucks Screen',
headerLeft: () => {
return null;
},
};
Cheers !
set headerLeft: null in the navigation Options. and this will remove the back button from the head as I did in the last line of code.
import React from 'react';
import { View } from 'react-native';
export const TrucksScreen = () => {
return (
<View>
....
</View>
);
});
TrucksScreen.navigationOptions = {
headerTitle: 'Trucks Screen',
headerLeft: null,
};
I hope it will help. Ask for doubts
According to the docs you can replace the header back button with whatever you want by passing options param in stack navigator . Do find the working example : expo-snack:
import * as React from 'react';
import { View, Text, Button, Image } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
function LogoTitle() {
return (
<Image
style={{ width: 50, height: 50 }}
source={require('#expo/snack-static/react-native-logo.png')}
/>
);
}
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerTitle: props => <LogoTitle {...props} />,
headerRight: () => (
<Button
onPress={() => alert('This is a button!')}
title="Info"
color="#00cc00"
/>
),
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
Hopeit helps. feel free for doubts
import React from 'react';
import { View, TouchableOpacity, Image, Text } from 'react-native';
import PropTypes from 'prop-types';
import style from '../../../utils/style';
import images from '../../../images/images';
class Header extends React.Component {
constructor(props) {
super(props);
}
onRightIconPress = () => {
if (this.props.onRightIconPress) {
this.props.onRightIconPress();
}
};
render() {
const { title, navigation, showBackIcon, showRightIcon, rightIcon } = this.props;
return (
<View style={style.headerrowcontainer}>
{/* Back Button*/}
{showBackIcon ? (
<TouchableOpacity onPress={() => navigation.goBack()}>
<Image resizeMode="contain" source={images.iconback} style={style.backimage} />
</TouchableOpacity>
) : (
<View />
)}
{/* Title */}
<Text style={style.titleheader}>{title}</Text>
{/* Right Icon */}
{showRightIcon ? (
<Image name={rightIcon} style={style.rightIcon} onPress={this.onRightIconPress} />
) : (
<View />
)}
</View>
);
}
}
Header.defaultProps = {
title: '',
};
Header.propTypes = {
title: PropTypes.string,
};
export default Header;
Home: {
screen: HomeScreen,
navigationOptions: {
headerLeft: null,
}
}
try setting headerLeft: null
Doesn't work in RN6.
TrucksScreen.navigationOptions = {
headerTitle: 'Trucks Screen',
headerLeft: () => {
return null;
},
};

Add custom icon to drawer navigation

I am trying to add custom icon to my CustomDrawerComponent, but nothing happen...
App.js :
const navigationOptions = {
headerTintColor: colors.white,
};
const drawerNavigationOption = ({ navigation }) => ({
...navigationOptions,
headerLeft: (
<TouchableOpacity onPress={() => navigation.toggleDrawer()}>
<View>
<Icon name="menu" size={24} color={colors.white} />
</View>
</TouchableOpacity>
),
});
const MapsStackNavigator = createStackNavigator({
MapsNavigator: {
screen: MapsScreen,
navigationOptions: drawerNavigationOption,
},
});
const AppDrawerNavigator = createDrawerNavigator(
{
Plans: MapsStackNavigator,
},
{
contentComponent: CustomDrawerMenu,
contentOptions: {
inactiveTintColor: colors.doveGrey,
activeTintColor: colors.doveGrey,
},
}
);
My CustomDrawerMenu.js :
export default class CustomDrawerMenu extends Component {
render() {
return (
<ScrollView
contentContainerStyle={{
flex: 1,
flexDirection: "column",
justifyContent: "space-between",
}}
>
<SafeAreaView forceInset={{ top: "always", horizontal: "never" }}>
{...}
<DrawerItems {...this.props} />
</SafeAreaView>
{...}
</ScrollView>
);
}
}
My MapsScreen :
export default class MapsScreen extends React.Component {
static navigationOptions = {
drawerIcon: (
<Image
style={{ width: 24, height: 24 }}
source={require("../../assets/icons/plan.png")}
/>
),
title: "Plans",
};
render() {
return (
<Text>My map screen</Text>
);
}
}
But absolutely nothing happened... I tried to add drawerIcon to my App.js > const navigationOptions but nothing happened aswell.
I do not really know where to place drawerIconm because I search on the doc, on some YouTubes video and when I reproduced the same, it does not work.
Thank you.
In the new version of react-navigation(5.x)
You have to do :
1-
import { createDrawerNavigator } from '#react-navigation/drawer';
import { NavigationContainer } from '#react-navigation/native';
import Icon from 'react-native-vector-icons/Ionicons';
2- Instead of using createDrawerNavigator you have to use Drawer.Navigator as below :
<NavigationContainer>
<Drawer.Navigator
initialRouteName="Products">
<Drawer.Screen name="Products" component={YOUR COMPONENT OR YOUR STACKNAVIGATOR} options={{
drawerIcon: config => <Icon
size={23}
name={Platform.OS === 'android' ? 'md-list' : 'ios-list'}></Icon>
}} />
<Drawer.Screen name="Orders" component={YOUR COMPONENT OR YOUR STACKNAVIGATOR} options={{
drawerIcon: config => <Icon
size={23}
name={Platform.OS === 'android' ? 'md-create' : 'ios-create'}></Icon>
}} />
</Drawer.Navigator>
</NavigationContainer>
I finally found the answer myself, you can not add drawerIcon to navigationOptions of the child-screen. You have to do like so :
const AppDrawerNavigator = createDrawerNavigator(
{
Home: {
screen: HomeStackNavigator,
navigationOptions: {
drawerIcon: (
<Image
style={{ width: 24, height: 24 }}
source={require("./assets/icons/plan.png")}
/>
),
},
},
And then in your HomeStack :
const HomeStackNavigator = createStackNavigator({
HomeNavigator: {
screen: HomeScreen,
navigationOptions: drawerNavigationOption,
},
});
Hope it'll serve to someone !
<Stack.Screen name="Feed" component={Feed} options={{ title: 'Feed',
drawerIcon: ({ focused, size }) => (
<Image
source={require('../../../assets/icons/icon-email.png')}
style={[{ height: 20, width: 20 }]}
/> )
}} />
const AppDrawerNavigator = createDrawerNavigator(
{
Home: {
screen: HomeStackNavigator,
navigationOptions: {
drawerIcon: (
<View>
<Image
style={{ width: 24, height: 24 }}
source={require("./assets/icons/plan.png")}
/>
</View>
),
},
},
Add before you will get original image style
hope this will save someone days..
import { NavigationContainer } from "#react-navigation/native";
<NavigationContainer>
<Drawer /> //import from your folder/file
</NavigationContainer>
drawer file
import { createDrawerNavigator } from "#react-navigation/drawer";
import DrawerContain from "./DrawerContain";
import StackNavigatore from "./stackNavigatore";
import ProductHome from "../product/ProductHome";
import Contact from "./ContactUs";
import About from "./About";
import HomeOrder from "./orderStack";
function DrawerNavigator() {
return (
<Drawer.Navigator
drawerContent={(props) => <DrawerContain {...props} />}
drawerContentOptions={
{
// activeTintColor: "#e91e63",
// itemStyle: { marginVertical: 5 },
}
}
>
<Drawer.Screen name="Home" component={StackNavigatore} />
<Drawer.Screen
name="Order"
component={HomeOrder}
/>
<Drawer.Screen name="Contact Us" component={Contact} />
<Drawer.Screen name="About Us" component={About} show={false} />
</Drawer.Navigator>
);
}
export default DrawerNavigator;
drawer container file
import {
DrawerContentScrollView,
DrawerItemList,
DrawerItem,
} from "#react-navigation/drawer";
import { View, StyleSheet } from "react-native";
import { useNavigation } from "#react-navigation/native";
import React from "react";
import Ionicons from "react-native-vector-icons/Ionicons";
import { Drawer, Text } from "react-native-paper";
function DrawerContain({ ...props }) {
// const navigation = useNavigation();
const image = require("../../assets/img/rupee.png");
return (
<>
<Drawer.Section>
<DrawerItem
icon={({ color, size }) => (
<Ionicons name="home-outline" color={color} size={size} /> <<--- with
vectore icon
)}
label="Sell prodcuts to customer"
// onPress={() => props.navigation.navigate('route to screen')}
/>
<Drawer.Item
icon={image} <<---- from local storage
label="Orders"
onPress={() => props.navigation.navigate("Order")}
/>
</>
)
}