React Navigation 4 Deep Linking is not working - react-native

I am using react-navigation-4. I was in expo and ejected from that using bare workflow.
Now I want to use deep linking so that when I want to click on a notification, it goes to a certain screen in my app.
I followed the instructions in https://reactnavigation.org/docs/4.x/deep-linking but when I using Linking.openURL("rnfarmer://submitrating/dd"); to open screen, nothing happens.
This is my App.js :
import React from "react";
import MyNavigator from "./navigation/MyNavigator";
export default function App() {
const prefix = 'rnfarmer://';
return <MyNavigator uriPrefix={prefix} />;
}
This is MyNavigator.js file :
...
export default createAppContainer(createStackNavigator({SubmitRating: {
screen: SubmitRatingScreen,
path: 'submitrating/:orderId'
}}));
and also I've added these lines to AndroidManifest.xml :
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="rnfarmer" />
</intent-filter>

Finally I found the answer.
I am using DrawerNavigator so I have a nested navigation and because of that I should add path to parent navigator and then to the child.
EDIT
Example :
This is your Main Navigator:
const MainNavigator = createDrawerNavigator({
MainNav: {
screen: FarmerNavigator,
path: "main"
} ,
ProfileNav: FillProfileNavigator,
MyOrdersNav: MyOrdersNavigator,
RatingNav: RatingNavigator,
RulesNav: RulesNavigator,
AboutAppNav: AbouAppNavigator
}, {
drawerPosition: "right",
contentComponent: DrawerContent,
contentOptions: {
activeTintColor: FarmerColors.colorPrimary,
itemsContainerStyle: {
marginVertical: 0,
},
iconContainerStyle: {
opacity: 1
}
}
});
And this is your Farmer Navigator:
const AsanZeraatNavigator = createStackNavigator({
ShowLand: ShowLandScreen,
ShowOrder: {
screen: ShowOrderScreen,
path: 'showorder/:params'
},
SubmitRating: {
screen: SubmitRatingScreen,
path: 'submitrating/:params',
}
});

Related

React navigation migration from v3 to v6

I've been assigned to a project where we need to upgrade react navigation from version 3 to version 6. Looking at the code I've found some strage stuff (or at least I think they are strange), the project consists of a Switch Navigator with two Stak Navigators inside like this:
const NavigatorOne = createStackNavigator(
{
NavOneScreenOne: {screen: NavOneScreenOne},
NavOneScreenTwo: {screen: NavOneScreenTwo},
NavOneScreenThree: {screen: NavOneScreenThree},
NavOneScreenFour: {screen: NavOneScreenFour}
},
{
headerMode: 'none',
navigationOptions: {
header: null,
},
defaultNavigationOptions: {
gesturesEnabled: false,
},
}
);
const NavigatorTwo = createStackNavigator(
{
NavTwoScreenOne: {screen: NavTwoScreenOne},
NavTwoScreenTwo: {screen: NavTwoScreenTwo},
NavTwoScreenThree: {screen: NavTwoScreenThree},
NavTwoScreenFour: {screen: NavTwoScreenFour}
},
{
headerMode: 'float',
navigationOptions: {},
defaultNavigationOptions: {
header: <Header />,
gesturesEnabled: false,
},
}
);
export default createAppContainer(
createSwitchNavigator(
{
App: NavigatorOne,
Visits: NavigatorTwo,
Login: PageLogin,
},
{
initialRouteName: 'Login',
backBehavior: 'none',
}
)
);
Then I have an AppNavigatorContainer, like this one:
const AppNavigatorContainer = ({ setNavigator }: { setNavigator: (n: NavigationContainerComponent) => void }) => {
const dispatch = useDispatch();
return (
<AppNavigator
ref={(navigatorRef) => {
NavigationService.setTopLevelNavigator(navigatorRef);
setNavigator(navigatorRef);
}}
onNavigationStateChange={(_prevState, currentState) => dispatch(setCurrentRoute(NavigationService.getActiveRouteName(currentState)))}
/>
);
};
and the App file like this:
const [navigator, setNavigator] = useState(null);
return (
<Provider store={ReduxConf.store}>
<PersistGate loading={null} persistor={ReduxConf.persistor}>
<ReduxNetworkProvider pingInterval={20000}>
<Root>
<StyledView>
<StatusBar hidden />
<Header />
<AppNavigatorContainer setNavigator={setNavigator} />
<Toolbar />
<Menu />
...
</StyledView>
...
</Root>
</ReduxNetworkProvider>
</PersistGate>
</Provider>
);
So basically its saving a reference to the AppNavigator inside a global file (NavigationService) so that it can be accessed everywhere, including Menu and Toolbar which aren't nested inside AppNavigatorContainer. Toolbar is a toolbar set at the bottom of the screen which changes buttons according if you are in the first or second stack.
As I see it, toolbar should be built using two TabNavigators (each one with its set of buttons/tabs) inside a StackNavigator, and Menu should be a DrawerNavigator (don't know if in version 3 of react navigation had these stacks), and should be nested inside the SwitchNavigator (in version 6 theres no Switch but the concept remains the same).
Is this a poorly written navigation structure? it feels it breaks many good coding rules... (the current structure of the project)

react navigation deep linking not working when use Tabs Stack

Version:
"dependencies": {
"react-native": "0.63.4",
"#react-navigation/bottom-tabs": "^5.11.2",
"#react-navigation/native": "^5.8.10",
"#react-navigation/stack": "^5.12.8",
}
Test website link test://info_register?token=1111 successfully, I can see route.params includes token
but when I get into my Tabs screen, and try to to use test://setting_register?token=1111, App just open it doesn't navigate to SettingScreen and route.params is undefined
I take reference from official document https://reactnavigation.org/docs/5.x/configuring-links
What is wrong with my deep linking for Tabs ?
Here is my code:
index.js
import * as React from 'react';
import {NavigationContainer} from '#react-navigation/native';
import LoginStack from './LoginStack';
import Linking from './Linking';
const AppContainer = () => {
return (
<NavigationContainer linking={Linking}>
<LoginStack />
</NavigationContainer>
);
};
export default AppContainer;
Linking.js
const config = {
screens: {
// set config for App init screen
PersonalInfoScreen: {
path: 'info_register/',
parse: {
token: (token) => `${token}`,
},
},
// set config for Tabs screen
Setting: {
screens: {
SettingScreen: 'setting_register/:token',
},
},
},
},
};
const Linking = {
prefixes: ['test://'],
config,
};
export default Linking;
LoginStack.js
import * as React from 'react';
import {useSelector} from 'react-redux';
import {createStackNavigator} from '#react-navigation/stack';
import LoginScreen from '../screens/Login/LoginScreen';
import PersonalInfoScreen from '../screens/Login/PersonalInfoScreen';
import TabStack from './TabStack';
const Stack = createStackNavigator();
const LoginStack = () => {
const {uid, userToken} = useSelector((state) => state.LoginRedux);
const showLoginFlow = uid === '' || userToken === '' ? true : false;
return (
<Stack.Navigator
initialRouteName={'LoginScreen'}
screenOptions={{headerShown: false, gestureEnabled: false}}>
{showLoginFlow ? (
<>
<Stack.Screen name="LoginScreen" component={LoginScreen} />
<Stack.Screen
name="PersonalInfoScreen"
component={PersonalInfoScreen}
/>
</>
) : (
<>
<Stack.Screen name="TabStack" component={TabStack} />
</>
)}}
</Stack.Navigator>
);
};
export default LoginStack;
TabStack.js
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
const Tab = createBottomTabNavigator();
const TabStack = () => {
return (
<Tab.Navigator
screenOptions={...mySetting}
tabBarOptions={...myStyle},
}}>
<Tab.Screen name={'Free'} component={FreeStack} />
<Tab.Screen name={'Video'} component={VideoStack} />
<Tab.Screen name={'News'} component={NewsStack} />
<Tab.Screen name={'Consultation'} component={ConsulationStack} />
<Tab.Screen name={'Setting'} component={SettingStack} />
</Tab.Navigator>
);
};
export default TabStack;
If review nested navigation https://reactnavigation.org/docs/5.x/configuring-links/#handling-nested-navigators docs.
You have this navigation tree for SettingScreen:
TabStack -> Setting -> SettingStack -> SettingScreen.
Routes configuration should match this tree also as below:
const config = {
screens: {
// set config for App init screen
PersonalInfoScreen: {
path: "info_register/",
parse: {
token: (token) => `${token}`,
},
},
// set config for Tabs screen
TabStack: {
screens: {
Setting: {
screens: {
SettingScreen: "setting_register/:token",
},
},
},
},
},
};
Just a note, it seems like whenever you are enabling debug-chrome configuration deep linking with react-navigation is not working, I disabled it and it worked!

Trouble migrating React Navigation v4 Deep Link configuration to React Navigation v5

I'm having some trouble migrating my deep-link from React Navigation v4 to React Navigation v5. 😊
For context, my deep linking has been working perfectly in React Navigation v5 with a tab bar navigator and stack navigators in each tab.
Here's what that looked like:
const MainApp = createBottomTabNavigator(
{
DiscoverTabStack: { screen: DiscoverTabStack, path: "" },
GroupTabStack: { screen: GroupTabStack, path: "" },
ProfileTabStack: { screen: ProfileTabStack, path: "" },
},
);
const DiscoverTabStack = createStackNavigator(
{
Discover: { screen: DiscoverScreen, path: "discover" },
DetailedActivityFromDeepLink: {
screen: DetailedActivityFromDeepLinkScreen,
path: "discover/activites/:id",
},
}
With React Navigation v4, I'm able to successfully deep link into the app to the correct place. However, I'm having some trouble with React Navigation v5. Below is how I'm approaching it with Reach Navigation v5.
const Tab = createBottomTabNavigator();
const DiscoverStack = createStackNavigator();
const prefixes = Linking.makeUrl("myapp://");
const linking = {
prefixes: [prefixes],
config: {
screens: {
DiscoverStack: {
path: "",
screens: {
Discover: {
path: "discover",
},
DetailedActivityFromDeepLink: {
path: "discover/activites/:id",
parse: {
id: (id) => `${id}`,
},
},
},
},
},
},
};
const DiscoverScreens = ({ navigation, route }) => {
return (
<DiscoverStack.Navigator mode="card">
<DiscoverStack.Screen
name="Discover"
component={DiscoverScreen}
/>
<DiscoverStack.Screen
name="DetailedActivityFromDeepLink"
component={DetailedActivityFromDeepLinkScreen}
/>
</DiscoverStack.Navigator>
);
};
render() {
return (
<Container>
<NavigationContainer linking={linking}>
<Tab.Navigator>
<Tab.Screen
name="Discover"
component={DiscoverScreens}
/>
</Tab.Navigator>
</NavigationContainer>
</Container>
);
}
Unfortunately, the above is not working. What may be wrong with my approach? How does one deep-link into an app that has tab bars with stack navigators in each tab?
I'm sure that this is a challenge for the majority of apps out there, so it'll be awesome for some help!! Thanks in advance!
What may be wrong with my approach?
In your root navigator (Tab.Navigator), you call your screen Discover, but in the linking config, you have written DiscoverStack.
The linking config needs to have the same names as you have your screens.

Adding <Icon> from react-native-elements to bottomTabNavigator shows error

I'm trying to add icons to my bottomTabNavigator using Icons from react-native-elements.
import { createBottomTabNavigator } from "react-navigation"
import { ServicesNavigator } from "./services-navigator"
import { AccountScreen } from "../screens/account-screen/account-screen"
import { Icon } from "react-native-elements"
export const BottomTabNavigator = createBottomTabNavigator({
services: {
screen: ServicesNavigator,
navigationOptions: {
tabBarLabel:"Services",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-build" type="Ionicon" size={10} />
)
},
},
account: { screen: AccountScreen },
})
The code above shows the following error in ios: Unexpected token, expected "</>/<=/>=" around the line where <Icon> is.
I've tried looking online but I can't seem to fix my problem. Any help would be appreicated!
those settings should not be within the RouteConfigs. Studying https://reactnavigation.org/docs/en/tab-based-navigation.html#customizing-the-appearance you should do more like
export const BottomTabNavigator = createBottomTabNavigator({
services: ServicesNavigator,
account: AccountScreen,
},
{
defaultNavigationOptions: () => {
tabBarIcon: () => <Icon name="ios-build" type="Ionicon" size={10} />
},
},
})
I finally found the problem. All this time my file's extension was .ts, which does not support jsx, instead of .tsx. Changing the file extension to .tsx did it for me.

React Navigation : Back button doesn't go to previous scene but to initialRouteName

I'm using react-native 0.50.3 with the react-navigation package. I've some issues to go to previous scene using the back button of the phone. Is it related to the last version of RN ?
This is the used code :
App.js defining drawer and stacknavigator :
import React from "react";
import {TabView, TabBarBottom} from 'react-navigation';
import { Platform } from "react-native";
import { Root } from "native-base";
import { StackNavigator, TabNavigator, DrawerNavigator } from "react-navigation";
import SideBar from "./main_scenes/sidebar/";
import HomeServices from "./main_scenes/services/";
import Profile from "./main_scenes/profile/";
import Splashscreen from "./main_scenes/home/splash";
import Services from "./main_scenes/services/servicesdetails/";
const Drawer = DrawerNavigator(
{
Splashscreen:{screen:Splashscreen},
Services:{screen:Services},
},
{
initialRouteName: "Splashscreen",
contentOptions: {
activeTintColor: "#e91e63"
},
contentComponent: props => <SideBar {...props} />
}
);
const Feedstack = StackNavigator(
{
Drawer: { screen: Drawer },
HomeServices:{screen:HomeServices},
Profile:{screen:Profile},
},
{
initialRouteName: "Drawer",
headerMode: "none",
}
);
export default () =>
<Root>
<Feedstack />
</Root>;
And this how i navigate from a scene to other :
From my scene called "services" to "servicesdetails". First, i've a array for all my data within the route as a variable
const datas = [
{
img: img1,
text: "Some text,
note: "Its time to build a difference . .",
route: "Services",
},
{
img: img2,
text: "Some text",
note: "Its time to build a difference . .",
route : "Another_one_for_test"
},
]
Then in the render(), i use :
<Content>
<List
dataArray={datas}
renderRow={data =>
<ListItem button thumbnail onPress={() => this.props.navigation.navigate(data.route)}>
<Left>
<Thumbnail square size={80} source={data.img} />
</Left>
<Body>
<Text >{data.text}</Text>
<Text numberOfLines={1} note>{data.note}</Text>
</Body>
</ListItem>}
/>
</Content>
My navigation goes very well, but from the scene details to the services's scene, cannot be back neither from the previous button, nor from the back button of the phone.
the function <Button transparent onPress={() => this.props.navigation.goBack()}> send me directly to "splashscreen" defined as the initialroutename in the app.js. Same for the back button.
Is there something i've done wrong ?
Thanks
Go back to previous screen and close current screen. back action creator takes in one optional parameter:
key - string or null - optional - If set, navigation will go back from the given key. If null, navigation will go back anywhere. Refer here
You have to provide the key to goBack from current screen if its nested.
this.props.navigation.goBack(this.props.navigation.state.key)}
you should pass the navigation prop to the different Navigators: using navigation={this.props.navigation}, more details here: https://reactnavigation.org/docs/intro/nesting#Nesting-a-Navigator-in-a-Component
as a side note, I would suggest using Native Splashcreen for iOS & Android, not just a component, and then Invert the logic of your routing,
to add a splash screen, you could use rn-toolbox: https://github.com/bamlab/generator-rn-toolbox/tree/master/generators/assets
const Drawer = DrawerNavigator(
{
Splashscreen:{screen:Splashscreen},
Services:{screen:Services},
Feedstack:{screen:Feedstack}
},
{
initialRouteName: "Feedstack",
contentOptions: {
activeTintColor: "#e91e63"
},
contentComponent: props => <SideBar {...props} />
}
);
const Feedstack = StackNavigator(
{
HomeServices:{screen:HomeServices},
Profile:{screen:Profile},
},
{
initialRouteName: "HomeServices",
headerMode: "none",
}
);