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

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.

Related

Expo BarCodeScanner keeps camera open upon navigation

I have a simple expo managed React Native project setup with react-navigation
I have 2 screens one of which is the Home screen and the other is a screen for QRCode scanner which uses expo's BarCodeScanner.
The issue here is that when navigating from the Home screen to the QRCode screen and back to the Home screen keeps the camera alive. I can see the activity in the status bar saying 'Expo Go is using your camera'
I tried various ways to tackle this,
Passing the screen as a render prop to Stack.Screen so it mounts every time we navigate, but still the same issue
Tried using the isFocused method to conditionally render the component but still no luck
<NavigationContainer fallback={<Text>Loading...</Text>}>
<Stack.Navigator
screenOptions={({ route, navigation }) => ({
headerShadowVisible: false,
headerTitle: () => (
<Text
style={{
fontSize: 30,
fontFamily: Font["900"],
}}
>
Test
</Text>
),
headerRight: () =>
route.name !== "QR" ? (
<Pressable onPress={() => navigation.navigate("QR")}>
<QrcodeIcon size={26} color="black" />
</Pressable>
) : null,
})}
>
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="QR" children={() => <QRCode />} />
</Stack.Navigator>
</NavigationContainer>
And the code for the QRCode component looks like the following:
const QRCode = () => {
const [hasPermission, setHasPermission] = useState<boolean>();
const [scanned, setScanned] = useState<boolean>(false);
const isFocused = useIsFocused();
const linkTo = useLinkTo();
useEffect(() => {
(async () => {
const { status } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(status === "granted");
})();
}, []);
const handleBarCodeScanned = ({ type, data }: BarCodeEvent) => {
setScanned(true);
linkTo(data);
};
if (hasPermission === null) {
return <Text>Requesting for camera permission</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={styles.container}>
{isFocused ? (
<BarCodeScanner
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={StyleSheet.absoluteFill}
/>
) : null}
</View>
);
};

route.params not returning a variable with React Navigation

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);

Can't pass parameters through React Navigation TabBar

Can't send any parameters with react-navigation 5x.
Tried everything on documentation. Don't know what's wrong.
I will share you all my route structure.
My ApplicationNavigator.js: I'm using drawer content with tabbar navigator at the same time. OrderNavigator is a tabnavigator, Dashboard is stacknavigator.
const ApplicationNavigator = () => {
const [isApplicationLoaded, setIsApplicationLoaded] = useState(false)
const applicationIsLoading = useSelector((state) => state.startup.loading)
return (
<Drawer.Navigator
drawerStyle={{ width: '100%' }}
drawerContent={(props) => <DrawerContent {...props} />}
>
<Drawer.Screen name="Dashboard" component={DashboardNavigator} />
<Drawer.Screen name="Order" component={OrderNavigator} />
</Drawer.Navigator>
)
}
export default ApplicationNavigator
My OrderNavigator.js: This is my tab.screen structure.
const ScreenA = () => {
return (
.....
<Stack.Navigator>
<Stack.Screen
options={headerStyle_1}
name="Orders"
component={IndexOrderContainer}
/>
</Stack.Navigator>
)
}
const ScreenB = () => {
....
return (
<Stack.Navigator>
<Stack.Screen
options={headerStyle_1}
name="New Order"
component={AddOrderContainer}
/>
</Stack.Navigator>
)
}
const OrderNavigator = () => {
return (
<Tab.Navigator headerMode={'none'}>
<Tab.Screen name="OrderList" component={ScreenA} />
<Tab.Screen name="NewOrder" component={ScreenB} />
</Tab.Navigator>
)
}
export default OrderNavigator
I'm trying to make redirect with code below. I'm using it with my order listing page, and trying to redirect to "order detail" page onclick. (with tab navigator.)
<TouchableOpacity
onPress={() =>
navigation.navigate('NewOrder', {
params: { user: 'jane' },
})
}
style={[styles.ListItem]}
button
key={`order${index}`}
>
And my response, when try to navigate with parameters is.
But you can see that my params is "undefined" with response.
const AddOrderContainer = ({ route, navigation }) => {
useEffect(() => {
console.log(route)
}, [route])
....
....
Object {
"key": "New Order-mafygLVPzFO1rVOhj1zVH",
"name": "New Order",
"params": undefined,
}

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.

Cannot call Element Props inside React Navigation Stack.Navigator

I am using React-Navigation v5 with Redux. I like to call my logOut action creator to trigger my log out function from my headerRight.
However, I can only access logOut from inside Home element and not inside HomeStack.
One idea I have is to also wrap my HomeStack with connect. I haven't tried it yet to know whether it can work or not. Even should it work, this isn't my preferred solution because i feel it makes my code very verbose
Anyone has a solution on how to access my logOut function from within my HomeStack? Thanks in advance
const Home = props => {
const { loading, error, data, subscribeToMore } = useQuery(FIND_BOOKS_QUERY);
console.log("home props", props);
return (
<View>
<Text> Welcome {props.user && props.user.name} </Text>
{loading && <Text>Loading...</Text>}
{error && <Text>Error: {error.message}</Text>}
{data &&
data.findBooks.map((x, index) => {
return (
<View key={index}>
<Text>
{x.title} - {x.author}
</Text>
</View>
);
})}
</View>
);
};
const HomeContainer = connect(
state => {
// console.log("home state", state);
return {
user: state.auth.user
};
},
{ logOut }
)(Home);
export const HomeStack = props => {
console.log("home stack props", props);
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"
component={HomeContainer}
options={{
headerRight: () => {
return (
<TouchableOpacity
onPress={() => {
// props.logOut // - cannot access logOut here as HomeStack props does not have logOut
console.log("exit");
}}
>
<Text>Exit</Text>
</TouchableOpacity>
);
}
}}
/>
</Stack.Navigator>
);
};
Wrapping my HomeStack with connect works. Its able to make available logOut inside H which allows me to call logOut inside headerRight.
However, such a method will be verbose because I will need to connect both H and Home to redux. Is there a more elegant way? Thanks
const Home = props => {
const { loading, error, data, subscribeToMore } = useQuery(FIND_BOOKS_QUERY);
console.log("home props", props);
return (
<View>
<Text> Welcome {props.user && props.user.name} </Text>
{loading && <Text>Loading...</Text>}
{error && <Text>Error: {error.message}</Text>}
{data &&
data.findBooks.map((x, index) => {
return (
<View key={index}>
<Text>
{x.title} - {x.author}
</Text>
</View>
);
})}
</View>
);
};
const HomeContainer = connect(
state => {
// console.log("home state", state);
return {
user: state.auth.user
};
},
{ logOut }
)(Home);
export const H = props => {
console.log("home stack props", props);
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"
component={HomeContainer}
options={{
headerRight: () => {
return (
<TouchableOpacity
onPress={() => {
props.logOut(); // now works OK
console.log("exit");
}}
>
<Text>Exit</Text>
</TouchableOpacity>
);
}
}}
/>
</Stack.Navigator>
);
};
export const HomeStack = connect(
state => {
// console.log("home state", state);
return {
user: state.auth.user
};
},
{ logOut }
)(H);