route.params not returning a variable with React Navigation - react-native

I'm attempting to pass a variable from one screen to another using React Navigation's route.params.
I've got this working on the screen immediately preceding it, but it's failing on the next screen and I cannot figure out why.
Here's the code:
setTimeout(() => {
console.log('here is the hid: ' + results.data.hid);
navigation.navigate('MainHome', {
hid: results.data.hid,
});
}, 2500);
The console log is correctly displaying the correct data in the console. This code leads to the next screen:
function Home({route, navigation}) {
const hid = route.params;
const [results, setResults] = useState([]);
const [errorMessage, setErrorMessage] = useState('');
const [loading, setLoading] = useState('loading');
console.log('Here is the hid that is retrieved from the route params on home:' + hid);
This console log is showing the hid as undefined.
Here is the expanded code for the referring screen:
function IntroOne({route, navigation}) {
const [results, setResults] = useState([]);
const [errorMessage, setErrorMessage] = useState('');
const [loading, setLoading] = useState('loading');
const {email, password} = route.params;
const CPRAPI = () => {
api
.get('create_account.php', {
params: {
email: email,
password: password,
},
})
.then(function (response) {
// handle success
setResults(response);
setLoading('success');
})
.catch(function (error) {
// handle error
console.log('ERROR :(');
console.log(error);
setErrorMessage(error);
});
};
useEffect(() => {
CPRAPI();
}, []);
if (loading != 'success') {
return (
<View style={styles.container}>
<Image
style={{width: windowWidth, maxHeight: 250}}
source={require('../components/parallel_universe.jpg')}
/>
<ActivityIndicator size={'large'} color={'#ee1c24'} />
<Text style={styles.header}>Loading...</Text>
</View>
);
} else {
if (results.data.intro_complete == 1) {
setTimeout(() => {
console.log('here is the hid: ' + results.data.hid);
navigation.navigate('MainHome', {
hid: results.data.hid,
});
}, 2500);
return (
<View style={styles.container}>
<Image
style={{width: windowWidth, maxHeight: 250}}
source={require('../components/parallel_universe.jpg')}
/>
<ActivityIndicator size={'large'} color={'#ee1c24'} />
<Text style={styles.header}>Almost Done...</Text>
</View>
);
}
Here is the expanded code for the receiving page:
function Home({route, navigation}) {
const hid = route.params.hid;
const [results, setResults] = useState([]);
const [errorMessage, setErrorMessage] = useState('');
const [loading, setLoading] = useState('loading');
console.log('Here is the hid that is retrieved from the route params on home:' + hid);
const CPRAPI = () => {
api
.get('home.php', {
params: {
hid: hid,
},
})
.then(function (response) {
// handle success
setResults(response);
setLoading('success');
})
.catch(function (error) {
// handle error
console.log('ERROR :(');
console.log(error);
setErrorMessage(error);
});
};
useEffect(() => {
CPRAPI();
}, []);
if (loading == 'loading') {
return (
<View style={styles.container}>
<Image
style={{width: windowWidth, maxHeight: 250}}
source={require('../components/parallel_universe.jpg')}
/>
<ActivityIndicator size={'large'} color={'#ee1c24'} />
<Text style={styles.header}>Loading...</Text>
</View>
);
} else {
return (
<View>
<Header
placement="center"
leftComponent={
<View>
<FontAwesomeIcon
style={{margin: 9}}
icon={['far', 'badge-dollar']}
/>
<Text>{results.data.home_screen[0].firstname}</Text>
</View>
}
centerComponent={{text: 'Hello, ', style: {color: '#fff'}}}
rightComponent={
<FontAwesomeIcon
style={{margin: 9}}
icon={['far', 'question-circle']}
/>
}
/>
<ScrollView>
<View style={styles.container}>
<Image
style={{width: windowWidth, maxHeight: windowHeight / 5}}
source={require('../components/parallel_universe.jpg')}
/>
<Text style={styles.header}>Hello, {}</Text>
<Text style={styles.textSmaller} />
<Text style={styles.textMuchSmaller}>
We will never spam you or sell your email.
</Text>
</View>
</ScrollView>
</View>
);
}
}
Here are my stacks:
const GettingStartedStack = createStackNavigator();
function GettingStartedScreen() {
return (
<GettingStartedStack.Navigator>
<GettingStartedStack.Screen
name="Getting Started"
component={GettingStarted}
options={{headerShown: false}}
/>
<GettingStartedStack.Screen
name="Question One"
component={gs1}
options={{title: 'Your Shadow Self'}}
/>
<GettingStartedStack.Screen
name="Defining Moment Narrative"
component={gs1entry}
/>
<GettingStartedStack.Screen
name="Question Two"
component={gs2}
options={{title: 'Credits & Money'}}
/>
<GettingStartedStack.Screen
name="Define Myself"
component={gs2entry}
options={{title: 'College'}}
/>
<GettingStartedStack.Screen
name="Concentration"
component={gs2Aentry}
options={{title: 'Concentration'}}
/>
<GettingStartedStack.Screen
name="Homeland"
component={gs3}
options={{title: 'Your Homeland'}}
/>
<GettingStartedStack.Screen
name="Choose Homeland"
component={gs3entry}
options={{title: 'Choose Your Homeland'}}
/>
<GettingStartedStack.Screen
name="Citizenship"
component={gs4}
options={{title: 'Your Citizenship'}}
/>
<GettingStartedStack.Screen
name="Choose Citizenship"
component={gs4entry}
options={{title: 'Choose Your Citizenship'}}
/>
<GettingStartedStack.Screen name="Banking" component={gs5} />
<GettingStartedStack.Screen
name="Choose Banking"
component={gs5entry}
options={{title: 'Choose Your Bank'}}
/>
<GettingStartedStack.Screen
name="Luck"
component={gs6}
options={{title: 'Are You Feeling Lucky?'}}
/>
<GettingStartedStack.Screen name="Parents" component={gs7} />
<GettingStartedStack.Screen name="Siblings" component={gs8} />
<GettingStartedStack.Screen name="Inheritance" component={gs9} />
<GettingStartedStack.Screen name="More Credits" component={moreCredits} />
</GettingStartedStack.Navigator>
);
}
const IntroStack = createStackNavigator();
function IntroStackScreen() {
return (
<IntroStack.Navigator>
<IntroStack.Screen
name="Welcome"
component={IntroOne}
options={{headerShown: false}}
/>
<IntroStack.Screen
name="Empire Universe"
component={IntroTwo}
options={{headerShown: false}}
/>
<IntroStack.Screen
name="Shadow Self"
component={IntroThree}
options={{headerShown: false}}
/>
</IntroStack.Navigator>
);
}
const HomeStack = createStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen
name="Home"
component={Home}
options={{headerShown: false}}
/>
</HomeStack.Navigator>
);
}
const FinancesStack = createStackNavigator();
function FinancesStackScreen() {
return (
<FinancesStack.Navigator>
<FinancesStack.Screen
name="Finances"
component={Finances}
options={{headerShown: false}}
/>
</FinancesStack.Navigator>
);
}
const Tab = createBottomTabNavigator();
function MainTabs() {
return (
<Tab.Navigator
screenOptions={({route}) => ({
tabBarIcon: ({focused, color, size}) => {
let iconName;
if (route.name === 'Cyclopedia') {
iconName = focused ? 'books' : 'books';
} else if (route.name === 'Big Think') {
iconName = focused ? 'head-side-brain' : 'head-side-brain';
} else if (route.name === 'Getting Started') {
iconName = focused ? 'key-skeleton' : 'key-skeleton';
} else if (route.name === 'CSX') {
iconName = focused ? 'chart-area' : 'chart-area';
} else if (route.name === 'Marketwire') {
iconName = focused ? 'analytics' : 'analytics';
} else if (route.name === 'Login') {
iconName = focused ? 'user-cog' : 'user-cog';
} else if (route.name === 'Map') {
iconName = focused ? 'map' : 'map';
} else if (route.name === 'Intro') {
iconName = focused ? 'home' : 'home';
} else {
iconName = focused ? 'books' : 'books';
}
// You can return any component that you like here!
return <FontAwesomeIcon icon={['far', iconName]} />;
},
})}
tabBarOptions={{
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
}}>
<Tab.Screen name="Home" component={HomeStackScreen} />
<Tab.Screen name="Finances" component={FinancesStackScreen} />
</Tab.Navigator>
);
}
const MainStack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<MainStack.Navigator>
<MainStack.Screen
name="Welcome"
component={IntroStackScreen}
options={{headerShown: false}}
/>
<MainStack.Screen
name="MainHome"
component={MainTabs}
options={{headerShown: false}}
/>
<MainStack.Screen
name="Getting Started"
component={GettingStartedScreen}
options={{headerShown: false}}
/>
</MainStack.Navigator>
</NavigationContainer>
);
}
Any thoughts about what could be causing this? I've tried a bunch of things, but just can't seem to get it to resolve properly.
I'm using:
React Native - 0.63.4
"#react-navigation/bottom-tabs": "^5.11.7",
"#react-navigation/native": "^5.9.2",
"#react-navigation/stack": "^5.14.1",
Thanks in advance!

In react-navigation 5 ... we need to specify what screen you wanna navigate to in case of nested-navigators...
Try this:
navigate('MainHome', {
screen: Home,
params: {
screen: 'Home',
params: {
hid: results.data.hid,
},
},
});

This will work.
function Home({route, navigation}) {
const hid = route.params.hid;
const [results, setResults] = useState([]);
const [errorMessage, setErrorMessage] = useState('');
const [loading, setLoading] = useState('loading');
console.log('Here is the hid that is retrieved from the route params on home:' + hid);

Related

Two tabs (Tab.Navigator) using one component to display lists, only data is different, Back button for the details page works wrong

when I tried to refactor the mobile app of 'Notes' from ‘JavaScript Everywhere’ book, a problem
The structure is like this:
RootNavigator(Stack.Navigator)
---AuthLoading(Screen)
---Auth(Stack.Navigator)
--SignIn(Screen)
--SignUp(Screen)
---App(Tab.Navigator)
--FeedStack(Stack.Navigator)
-FeedScreen(Screen)
-NoteScreen(Screen)
--MyNotesStack(Stack.Navigator)
-MyNotesScreen(Screen)
-NoteScreen(Screen)
--FavoritesStack(Stack.Navigator)
-FavoritesScreen(Screen)
-NoteScreen(Screen)
--SettingsStack(Stack.Navigator)
When a user login, the default tab is ‘Feed’ which goes to ‘FeedStack’, and FeedScreen list all the notes created by all the users, click one item of the notes, it goes to a NoteScreen, display the details of that ‘Note’, everything goes well.
When the user choose ‘MyNotes’ tab which goes to ‘MyNoteStack’, it list the notes created by the current user, click one of the ‘note’ item, it goes to NoteScreen, display the details of that ‘note’. However, now, the default focus of the Tab.Navigator is ‘Feed’, and when I click back button in the NoteScreen, it goes back to ‘FeedStack’ which displays all the notes. It is weird!
I can’t understand why I go to the NoteScreen from ‘MyNotes’, but back button leads it to ‘Feed’, how to fix this problem?
And the code is as follows.
In index.js (RootNavigator)
const Stack = createNativeStackNavigator();
const Tab = createBottomTabNavigator();
const AuthStack = createNativeStackNavigator();
const feedStack = createNativeStackNavigator();
const myNotesStack = createNativeStackNavigator();
const favoritesStack = createNativeStackNavigator();
const settingsStack = createNativeStackNavigator();
function FeedStack () {
return (
<feedStack.Navigator
screenOptions={
{headerShown:false}
}
>
<feedStack.Screen name="FeedScreen" component={FeedScreen} />
<feedStack.Screen name="NoteScreen" component={NoteScreen} options={{headerShown:true}}/>
</feedStack.Navigator>
);
}
function MyNotesStack () {
return (
<myNotesStack.Navigator
screenOptions={
{headerShown:false}
}
>
<myNotesStack.Screen name="MyNotesScreen" component={MyNotesScreen} />
<myNotesStack.Screen name="Note" component={NoteScreen} options={{headerShown:true}} />
</myNotesStack.Navigator>
);
}
function FavoritesStack () {
return (
<favoritesStack.Navigator
screenOptions={
{headerShown:false}
}
>
<favoritesStack.Screen name="FavoritesScreen" component={FavoritesScreen} />
<favoritesStack.Screen name="Note" component={NoteScreen} options={{headerShown:true}}/>
</favoritesStack.Navigator>
);
}
function SettingsStack () {
return (
<settingsStack.Navigator
screenOptions={
{headerShown:false}
}
>
<settingsStack.Screen name="SettingsScreen" component={SettingsScreen} />
</settingsStack.Navigator>
);
}
const TabNavigator = () => {
return (
<Tab.Navigator
initialRouteName="MyNotes"
activeColor='#f0f'
inactiveColor='#555'
barStyle={{
backgroundColor:'#999'
}}
screenOptions={({route}) => ({
headerShown: false,
tabBarIcon:({focused, size, color}) => {
let iconName;
if( route.name === 'FeedStack') {
iconName = 'home';
} else if (route.name === 'MyNotesStack') {
iconName = 'bed';
} else if (route.name === 'FavoritesStack') {
iconName = 'star'
} else {
iconName = 'spa'
}
color = focused ? '#f0f' : "#555";
size = focused ? 24 : 20;
return <FontAwesome5 name={iconName} size={size} color={color}/>;
},
})}
>
<Tab.Screen name='FeedStack' component={FeedStack} options={{headerShown: false}} />
<Tab.Screen name='MyNotesStack' component={MyNotesStack} options={{headerShown: false}} />
<Tab.Screen name='FavoritesStack' component={FavoritesStack} options={{headerShown: false}}/>
<Tab.Screen name='SettingsStack' component={SettingsStack} options={{headerShown: false}} />
</Tab.Navigator>
);
};
const Auth= () => {
return (
<AuthStack.Navigator
screenOptions={{headerShown:false}}
>
<AuthStack.Screen name='signIn' component={SignIn}></AuthStack.Screen>
</AuthStack.Navigator>
);
};
const RootNavigator = () => {
return (
<Stack.Navigator initialRouteName='AuthLoading'>
<Stack.Screen name='AuthLoading'
component={AuthLoading}
options={{title:'AuthLoading'}}
>
</Stack.Screen>
<Stack.Screen name='Auth'
component={Auth}
options={{
title: 'Auth',
headerStyle: {
backgroundColor: '#f4511e',
},
headerBackVisible: false,
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
}}
>
</Stack.Screen>
<Stack.Screen name='App'
component={TabNavigator}
options={{
title: 'App',
headerStyle: { backgroundColor: '#f4511e'},
headerBackVisible:false,
headerTintColor: '#fff',
headerTitleStyle: {fontWeight: 'bold'},
}}
>
</Stack.Screen>
</Stack.Navigator>
);
};
export default RootNavigator;
In FeedScreen.js:
const FeedScreen = () => {
const { data, loading, error } = useQuery(GET_NOTES);
// if the data is loading, our app will display a loading indicator
if(loading)
return <Loading />;
if(error)
return <Text>Error loading notes.</Text>;
// if the query is successful and there are notes, return the feed of notes
return (
<NoteFeed notes={data.notes} />
);
};
In MyNotesScreen.js
const MyNotesScreen = () => {
const { data, loading, error } = useQuery(GET_MY_NOTES);
// if the data is loading, our app will display a loading indicator
if(loading)
return <Loading />;
if(error)
return <Text>Error loading MyNotes.</Text>;
// if the query is successful and there are notes, return the feed of notes
// else if the query is successful and there aren't notes, display a message
if(data.me.notes.length !== 0) {
return <NoteFeed notes={data.me.notes} />;
} else {
return <Text>No notes yet</Text>;
}
// If I don't use <NoteFeed> here, for example, show a button then go to <NoteScreen> it is ok.
// return (
// <View style={styles.container}>
// <Text>My Notes Screen</Text>
// use self-defined button
// <JereButton
// onPress={() => navigation.navigate('Note',{id:'63b94da5ccf7f90023169c3d'})}
// title="Go to a note"
// color={"#882"}
// />
// </View>
// );
};
In NoteFeed.js
const NoteFeed = props => {
// only screen components receive navigation prop automatically!
// if you wish to access the navigation prop in any of your components, you may use the useNavigation hook.
const navigation = useNavigation();
return (
<View style={styles.container}>
<FlatList
data={props.notes}
keyExtractor = {({id}) => id.toString()}
renderItem = {({item}) => (
<Pressable style={styles.feedview}
onPress={() => navigation.navigate('NoteScreen',{id: item.id})}
>
<Text style={styles.text}>{item.content}</Text>
</Pressable>
)}
/>
</View>
);
};
In NoteScreen.js
const NoteScreen = ({navigation, route}) => {
const {id} = route.params;
const { data, loading, error } = useQuery(GET_NOTE, {variables:{id}});
// if the data is loading, our app will display a loading indicator
if(loading)
return <Loading />;
if(error)
return <Text>Error Note not found.</Text>;
return (
<Note note={data.note} />
);
};
Thank you for your help.
I tried to replace useNavigation() to props solution, the issue is the same. Then I tried to do not use in 'MyNotes' to show the ‘note’, it is OK, but it doesn’t comply with the design.

Troubleshooting Navigation Issues on the Onboarding to HomeScreen Transition

Hello I couldn't navigate from Onboarding to HomeScreen. I'm not sure what I do wrong. It gives error such as The 'navigation' object hasn't been initialized yet. This might happen if you don't have a navigator mounted, or if the navigator hasn't finished mounting. See https://reactnavigation.org/docs/navigating-without-navigation-prop#handling-initialization
for more details.
//AppRoot.js
const [isFirstLaunch, setFirstLaunch] = useState(null);
useEffect(() => {
AsyncStorage.getItem("onboardingCompleted").then((value) => {
if (value == null) {
setFirstLaunch(true);
} else {
setFirstLaunch(false);
}
});
}, []);
return (
<NavigationContainer
ref={navigationRef}
onReady={() =>
(routeNameRef.current =
navigationRef?.current?.getCurrentRoute()?.name ?? "")
}
onStateChange={() => {
const previousRouteName = routeNameRef.current;
const currentRouteName =
navigationRef?.current?.getCurrentRoute()?.name;
trackScreenView(previousRouteName, currentRouteName);
console.log(previousRouteName, " -> ", currentRouteName);
// Save the current route name for later comparison
routeNameRef.current = currentRouteName;
}}
theme={themeToSet === "dark" ? DarkModeTheme : LightModeTheme}
>
<Loader visible={isLoading} />
{isFirstLaunch == false ? <HomeScreen /> : <OnboardingScreen />}
</NavigationContainer>
);
// Onboarding
const OnboardingScreen = () => {
const navigation = useNavigation();
const [currentPage, setCurrentPage] = useState(0);
const pages = [
<WelcomeScreen onGetStarted={() => setCurrentPage(1)} />,
<PersonalizationScreen1 />,
<PersonalizationScreen2 />,
<NotificationScreen />,
<WidgetScreen />,
<PaywallScreen />,
<EndScreen />,
];
const onContinue = () => {
if (currentPage === pages.length - 1) {
AsyncStorage.setItem("onboardingCompleted", "true");
} else {
setCurrentPage(currentPage + 1);
}
};
return <View>{React.cloneElement(pages[currentPage], { onContinue })}</View>;
};
export default OnboardingScreen;
//HomeScreen
const Tab = createBottomTabNavigator();
const HomeBottomNavigation = () => {
const { colors } = useTheme();
const { t } = useTranslation();
return (
<Tab.Navigator
id="BottomNavigation"
initialRouteName="Users"
screenOptions={({ route, navigation }) => ({
headerShown: false,
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === "UsersStack") {
iconName = focused ? "people" : "people-outline";
} else if (route.name === "SettingsStack") {
iconName = focused ? "settings" : "settings-outline";
} else if (route.name === "Feedback") {
iconName = focused ? "newspaper" : "newspaper-outline";
} else if (route.name === "More") {
iconName = focused ? "apps" : "apps-outline";
}
return <Icon name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: colors.text,
tabBarInactiveTintColor: "gray",
unmountOnBlur: true,
})}
>
<Tab.Screen
name="UsersStack"
component={UsersStackScreen}
options={{ headerShown: false, title: t("users") }}
/>
<Tab.Screen
name="SettingsStack"
component={SettingsStackScreen}
options={{ headerShown: false, title: t("settings") }}
/>
<Tab.Screen
name="Feedback"
component={FeedbackScreen}
options={{ headerShown: false, title: t("feedback") }}
/>
<Tab.Screen
name="More"
component={MoreScreen}
options={{ headerShown: false, title: t("more") }}
/>
</Tab.Navigator>
);
};
export default HomeBottomNavigation;
//Onboarding Stack
const Stack = createNativeStackNavigator();
const OnboardingStackNavigation = () => {
return (
<Stack.Navigator
id="OnboardingNavigation"
initialRouteName="Onboarding"
screenOptions={({ route, navigation }) => {
({ headerShown: false });
}}
>
<Stack.Screen
name="Onboarding"
component={OnboardingScreen}
options={{ headerShown: false }}
/>
<Stack.Screen
name="Home"
component={UsersScreen}
options={{ headerShown: false }}
/>
</Stack.Navigator>
);
};
I have tried passing setFirstLaunch to onboarding screen and tried to manage that.
I have tried navigating inside Onboarding.
I have tried button triggered navigation.

React Native: How to use deep linking with iOS?

I'm trying to use deep linking in my react native app for ios. I've been following this document by React Navigation.
I added what was needed to my AppDelegate.m and to Xcode:
However I'm confused on how to implement this in my App.js:
const AuthStack = createStackNavigator();
const AuthStackScreen = () => (
<AuthStack.Navigator >
<AuthStack.Screen
name="Ingresar"
component={Login}
options = {{
headerShown: false,
title: "Bienvenido"
}}/>
<AuthStack.Screen name="CrearCuenta"
component={Signup}
options={{title: "Crear cuenta"}}/>
</AuthStack.Navigator>
);
const Tabs = createBottomTabNavigator();
const HomeStack = createStackNavigator();
const DonationsStack = createStackNavigator();
const DonateStack = createStackNavigator();
const InstitutionsStack = createStackNavigator();
const ProfileStack = createStackNavigator();
const DonationsStackScreen = () => (
<DonationsStack.Navigator>
<DonationsStack.Screen name="Pedidos" component={DonationsScreen}/>
<DonationsStack.Screen name="Realizar donación" component={DonationFormScreen}/>
<DonationsStack.Screen name="Donación confirmada" component={DonationConfirmationScreen}
options = {{
headerShown: false
}}/>
</DonationsStack.Navigator>
);
// I omit some of the stack screens here.
const TabsScreen = () => (
<Tabs.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) =>
{
let iconName;
if (route.name === 'Home') {
iconName = focused ? 'home' : 'home-outline';
return <MaterialCommunityIcons name={iconName} size={size} color={color}/>;
} else if (route.name === 'Pedidos') {
iconName = focused ? 'ios-list-box' : 'ios-list';
}
else if (route.name === 'Donar') {
iconName = focused ? 'gift' : 'gift-outline';
return <MaterialCommunityIcons name={iconName} size={size} color={color}/>;
} else if (route.name === 'Perfil') {
iconName = focused ? 'user-alt'
: 'user';
return <FontAwesome5 name={iconName} size={size-4} color={color}/>;
} else if (route.name === 'Instituciones') {
iconName = 'md-business';
}
return <Ionicons name={iconName} size={size} color={color} />;
},
})}
tabBarOptions={{
activeTintColor: '#013773',
inactiveTintColor: 'gray',
}}>
<Tabs.Screen name="Home" component={HomeStackScreen}/>
<Tabs.Screen name="Pedidos" component={DonationsStackScreen}/>
<Tabs.Screen name="Donar" component={DonateStackScreen}/>
<Tabs.Screen name="Instituciones" component={InstitutionsStackScreen}/>
<Tabs.Screen name="Perfil" component={ProfileStackScreen}/>
</Tabs.Navigator>
);
const RootStack = createStackNavigator();
const RootStackScreen = ({user}) => (
<RootStack.Navigator headerMode="none">
{user ? (
<RootStack.Screen
name="App"
component={TabsScreen}
options={{animationEnabled: false}}/>
) : (
<RootStack.Screen
name="Auth"
component={AuthStackScreen}
options={{animationEnabled: false}}/>
)}
</RootStack.Navigator>
);
export default function ponte() {
const [isLoading, setIsLoading] = React.useState(false);
const [user, setUser] = React.useState(null);
// Handle user state changes
function onAuthStateChanged(user) {
setUser(user);
if (isLoading) setIsLoading(false);
}
if (isLoading) return null;
useEffect(() => {
SplashScreen.hide();
const subscriber = auth().onAuthStateChanged(onAuthStateChanged);
return subscriber; // unsubscribe on unmount
}, []);
const authContext = React.useMemo(() => {
return {
signIn: (email, password) =>
auth()
.signInWithEmailAndPassword(email.email, password.password)
.then(res => {
setIsLoading(false);
setUser(res.user.uid);
})
,
signUp: () => {
setIsLoading(false);
setUser("test");
},
signOut: () => {
setIsLoading(false);
auth().signOut().then(() => console.log('User signed out!'));
setUser(null);
}
};
}, []);
/*
Here comes my deeplinking.
What I need to do is that when the user clicks on my URL
it goes to Pedidos --> Realizar donación with a parameter called request.
All of this happens inside the DonationsStack
*/
const deepLinking = {
prefixes: ['https://demoApp.com', 'demoApp://'],
config: {
Home: 'HomePath',
RealizarDonacion: {
path: 'Pedidos/Realizar donación/:request',
params: {
request: null,
}
}
} ,
};
return(
<AuthContext.Provider value={authContext}>
<NavigationContainer linking={deepLinking}>
<RootStackScreen user={user} />
</NavigationContainer>
</AuthContext.Provider>
);
}
As you see at the end I provide my deepLinking component to the NavigationContainer.
However when I type demoApp://Pedidos/Realizar donación/44 in Safari I don't get redirected to my app.
I'm not convinced about that space inside the path, however it doesn't work when I create a deepLink to Pedidos only either.
I need my URL to open my app and inside the DonationsStack navigate to Pedidos (DonationsScreen) --> Realizar donación (DonationFormScreen)
Update: My app opens but I don't get redirected to any screen.

React Native Context, how to share context beetwing multiple nested files and components

I'm quiete new to react native, and im stuck on passing context between components in different files
basically im building login flow following the react navigation auth-flow https://reactnavigation.org/docs/auth-flow/
my scenario looks as follow:
in App.js
a stack screen with Login/Register/Home, showing Login/Register or Home based on login status
the Home Screen is made by a component which is a drawer, using a custom drawer and two component (Home and About)
//VARIOUS IMPORT
const Drawer = createDrawerNavigator();
const HeaderOption = () => ({
headerShown: false,
// animationTypeForReplace: state.isSignout ? 'pop' : 'push',
});
const AppStack = createStackNavigator();
const AuthContext = createContext();
//THE DRAWER FOR HOME
function DrawerNavigator(props) {
return (
<Drawer.Navigator
initialRouteName="Home"
drawerContent={(props) => MyDrawer(props)}
>
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="About" component={About} />
</Drawer.Navigator>
);
}
//MAIN APP
export default function App({ navigation }) {
const [state, dispatch] = useReducer(
(prevState, action) => {
switch (action.type) {
case 'RESTORE_TOKEN':
return {
...prevState,
userToken: action.token,
isLoading: false,
};
case 'SIGN_IN':
return {
...prevState,
isSignout: false,
userToken: action.token,
};
case 'SIGN_OUT':
return {
...prevState,
isSignout: true,
userToken: null,
};
}
},
{
isLoading: true,
isSignout: false,
userToken: null,
}
);
useEffect(() => {
// Fetch the token from storage then navigate to our appropriate place
const bootstrapAsync = async () => {
let userToken;
try {
userToken = await AsyncStorage.getItem('userToken');
} catch (e) {
}
dispatch({ type: 'RESTORE_TOKEN', token: userToken });
};
bootstrapAsync();
}, []);
const authContext = useMemo(
() => ({
signIn: async (data) => {
// LOGIN PROCEDURE
dispatch({ type: 'SIGN_IN', token: 'dummy-auth-token' });
},
signOut: () => dispatch({ type: 'SIGN_OUT' }),
signUp: async (data) => {
// SUBSCRIBE PROCEDURE
dispatch({ type: 'SIGN_IN', token: 'dummy-auth-token' });
},
}),
[]
);
if (state.isLoading) {
// We haven't finished checking for the token yet
return (
<View>
<Text>Loading</Text>
</View>
);
}
return (
<AuthContext.Provider value={authContext}>
<NavigationContainer>
<AppStack.Navigator initialRouteName="Login">
{state.userToken == null ? (
<>
<AppStack.Screen
name="Login"
component={LoginScreen}
options={HeaderOption}
/>
<AppStack.Screen
name="Register"
component={RegisterScreen}
options={HeaderOption}
/>
</>
) : (
<AppStack.Screen
name="HomeApp"
component={DrawerNavigator}
options={HeaderOption}
/>
)}
</AppStack.Navigator>
</NavigationContainer>
</AuthContext.Provider>
);
}
in LoginScreen.js
the effective login screen (which is showed at app startup if not logged in)
//import
export default function LoginScreen(props) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const { signIn } = useContext(AuthContext);
return (
<View
style={{
flex: 1,
backgroundColor: Constants.MAIN_GREEN,
}}
>
<View style={{ ...styles.container }}>
<StatusBar hidden={true} />
<View style={{ ...styles.logoContainer }}>
<Image
style={styles.logoIcon}
source={require('../assets/logo_popeating_amp.png')}
/>
</View>
<View style={{ ...styles.inputContainer }}>
<Image
style={styles.inputIcon}
source={require('../assets/mail.png')}
/>
<TextInput
autoFocus={true}
placeholder="Email address"
onChangeText={(email) => setEmail(email)}
value={email}
label="Email"
style={styles.inputs}
keyboardType={'email-address'}
/>
</View>
<View style={{ ...styles.inputContainer }}>
<Image
style={styles.inputIcon}
source={require('../assets/password.png')}
/>
<TextInput
placeholder="Password"
onChangeText={(password) => setPassword(password)}
value={password}
secureTextEntry={true}
label="Password"
style={styles.inputs}
/>
</View>
<TouchableHighlight
style={[styles.buttonContainer, styles.loginButton]}
onPress={() => signIn({ email, password })}
underlayColor={Constants.HI_COLOR}
>
<Text style={styles.loginText}>LOGIN</Text>
</TouchableHighlight>
<TouchableHighlight
style={styles.buttonContainer}
onPress={() => props.navigation.navigate('HomeApp')}
underlayColor={Constants.HI_COLOR}
>
<Text>Forgot your password?</Text>
</TouchableHighlight>
<TouchableHighlight
style={styles.buttonContainer}
onPress={() => props.navigation.navigate('Register')}
underlayColor={Constants.HI_COLOR}
>
<Text>Register</Text>
</TouchableHighlight>
</View>
</View>
);
}
const styles = StyleSheet.create({
//styles
});
in DrawerContent.js
the drawer for the home which contain a link to Home, a link to About, a link to Logout
in Home.js
the main page which is the initialroute of the Drawer
every time i try to start the app
the error is
Unhandled promise rejection: ReferenceError: Can't find variable: AuthContext
it seems LoginScreen cant access AuthContext, how can i have AuthContext available to other components between files?
You can place the context creation in a separate file
//AuthContext.js
const AuthContext = createContext();
export default AuthContext;
In app.js you can simply import this and use this
import AuthContext from './AuthContext.js';
You can do the same for login.js as well
Then it will work as expected.

React navigation 5 ( navigate to another stack Screen)

this is my appNavigator: I divide into 3 stackScreen include HomeStack, SettingsStack and ProfileStack. AuthStack contain SignUp and Signin Screen, and i create bottom tab contain 3 StackScreen above
const HomeStack = createStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator headerMode="none">
<HomeStack.Screen name="Home" component={HomeScreen} />
<HomeStack.Screen name="Details" component={DetailsScreen} />
</HomeStack.Navigator>
);
}
const SettingsStack = createStackNavigator();
function SettingsStackScreen() {
return (
<SettingsStack.Navigator>
<SettingsStack.Screen name="Settings" component={SettingsScreen} />
<SettingsStack.Screen name="Details" component={DetailsScreen} />
</SettingsStack.Navigator>
);
}
const ProfileStack = createStackNavigator();
function ProfileStackScreen({navigation}) {
return (
<ProfileStack.Navigator>
<ProfileStack.Screen name="Profile" component={ProfileScreen} />
</ProfileStack.Navigator>
);
}
// ** AUTH ** //
const AuthStack = createStackNavigator();
function AuthStackScreen() {
return (
<AuthStack.Navigator headerMode="none">
<AuthStack.Screen name="SignIn" component={LoginScreen} />
<AuthStack.Screen name="SignUp" component={SignUpScreen} />
</AuthStack.Navigator>
);
}
// ** APP ** //
const AppStack = createBottomTabNavigator();
function AppStackScreen() {
return (
<AppStack.Navigator name="mainApp">
<AppStack.Screen name="Dashboard" component={HomeStackScreen} />
<AppStack.Screen name="Favorite" component={SettingsStackScreen} />
<AppStack.Screen name="Profile" component={ProfileStackScreen} />
</AppStack.Navigator>
);
}
// ** ROOT ** //
const RootStack = createStackNavigator();
const RootStackScreen = ({userToken}) => {
return (
<RootStack.Navigator headerMode="none">
<RootStack.Screen name="Auth" component={AuthStackScreen} />
<RootStack.Screen name="App" component={AppStackScreen} />
</RootStack.Navigator>
);
};
export default function AppNavigator() {
const [loading, setloading] = React.useState(true);
const [userToken, setUserToken] = React.useState();
React.useEffect(() => {
setTimeout(() => {
setloading(false);
}, 1000);
});
if (loading) {
return <SplashScreen />;
}
// })
return (
<NavigationContainer>
<RootStackScreen />
</NavigationContainer>
);
}
and this is my Login Screen :
const LoginScreen = ({ navigation, props }) => {
console.tron.log("debug: LoginScreen -> props", props, navigation)
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const [error, setError] = React.useState('');
const [loading, setLoading] =React.useState(false)
const handleLogin = () => {
if (email === '' && password === '') {
Alert.alert('Enter details to signin!')
} else {
setLoading(true)
firebase
.auth()
.signInWithEmailAndPassword(email,password)
.then((res) => {
console.log(res)
console.log('User logged-in successfully!')
setLoading(false)
setEmail('')
setPassword('')
navigation.navigate("AppStack", {screen: "Dashboard"})
})
.catch(error => setError(error.message))
}
}
return (
<ImageBackground source={require('../images/background.jpg')} style={styles.imageBack}>
<View style={styles.area1}>
<Image
source={require('../images/vaccines.png')}
style={styles.logo} />
<View style={styles.box}>
<TextInput
placeholder='Email'
onChangeText={email => setEmail(email)}
value={email}
maxLength={15}
/>
</View>
<View style={styles.box}>
<TextInput
placeholder='Password'
secureTextEntry={true}
onChangeText={password => setPassword(password)}
value={password}
maxLength={15}
/>
</View>
<BlockIcon />
<TouchableOpacity style={styles.buttonLogin} onPress={handleLogin}>
<Text style={styles.text1}>Sign In</Text>
</TouchableOpacity>
<View style={{ flexDirection: 'row', justifyContent: 'center', marginTop: 50 }}>
<Text style={styles.text2}> If you don't have an account ?</Text>
<TouchableOpacity onPress={() => navigation.push('SignUp')}>
<Text style={styles.text3}> Sign Up </Text>
</TouchableOpacity>
</View>
</View>
</ImageBackground>
)
}
I navigate at navigation.navigate("AppStack", {screen: "Dashboard"})
when I login successful. I want to navigate to AppStack (bottomtab with initial Screen name is Dasboard) I try to use nesting navigator but unsuccessful. I also try to use navigation.navigate('HomeScreen'), but it not work. Anyone can help me =((. Thanks
I know this is a month old but maybe this will help someone else.
Looks like you're close. In your RootStackScreen, you have two screens: "Auth" and "App". And it sounds like you want to go to your "App" screen from your "Auth" screen. You just need to use the name of the screen.
navigation.navigate("App", {screen: "Dashboard"})