Trouble migrating React Navigation v4 Deep Link configuration to React Navigation v5 - react-native

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.

Related

Basic deep linking not working with React Navigation and Redux

EDIT:
I am wondering if this issue is related to the fact that I have the redux store wrapping the appContainer. Is there another way I am supposed to handle deep linking when using Redux?
I cannot get my deep links to work. They open up the app but do not direct to any page. I have followed directions exactly as is listed here https://reactnavigation.org/docs/en/bottom-tab-navigator.html
I am not sure if it is because of the createSwitchNavigator. I can't figure out how to troubleshoot to figure this out either.
const AppSwitchNavigator = createSwitchNavigator({
Open: { screen: AuthStackNavigator },
Home: {
screen: MainStackNavigator,
path: ''
}
})
const AppContainer = createAppContainer(AppSwitchNavigator)
const PREFIX = 'myApp://';
const App = () => {
return (
<Provider store={store}>
<AppContainer
uriPrefix={PREFIX}
/>
</Provider>
)
}
In MainStackNavigator I have this...
const MainStackNavigator = createStackNavigator(
{
MainTabNavigator: {
screen: MainTabNavigator,
path: ''
},
Contact: {
screen: Contact,
path: 'contact',
},
...
But when i go to myApp://contact - it opens the app but doesn't go the contact screen, and of course, any of the screens in the TabNavigator don't get anywhere either.

How to implement Drawer and TabBar in StackNavigator

I always use react-native-router-flux for navigation, but on this project I need to use react-navigation and I got some troubles with it. I need to implement drawer and tabBar inside stack navigator.
Problems:
I use header component from native-base library but i can't open
drawer.
How to use my own customized component for drawer and tabBar?
Maybe I need to chage structure. I will consider any recommendations how to improve structure.
I used version 3 of react-navigation.
My code:
const AppStackNavigator = createStackNavigator({
loginFlow: {
screen: createStackNavigator({
intro: { screen: Intro },
login: { screen: Login },
registration: { screen: Registration },
}),
navigationOptions: {
header: null
}
},
mainFlow: {
screen: createStackNavigator({
MyDrawer: createDrawerNavigator({
Dashboard: {
screen: Home,
},
first: {
screen: first,
},
second: {
screen: second
},
third: {
screen: third
},
last: {
screen: last
}
}),
// settings: { screen: SettingsScreen },
someTab: {
screen: createBottomTabNavigator({
main: { screen: Home },
firsrTab: { screen: Screen1 },
secondTab: { screen: Screen2 },
thirdTab: { screen: Screen3 },
nextTab: { screen: Screen4 }
}),
navigationOptions: {
header: null
},
}
}),
navigationOptions: {
header: null
}
}
});
const AppContainer = createAppContainer(AppStackNavigator);
import React from 'react';
import { Header, Left, Icon, Right } from 'native-base';
const CustomHeader = (props) => {
return(
<Header>
<Left>
<Icon
name='menu'
onPress={() => {this.props.navigation.openDrawer()}}
/>
</Left>
</Header>
)
}
export { CustomHeader }
You might wanna consider the SwitchNavigator for the authentication flow instead of a Stack at the top as it replaces the routes so that you can never navigate back to the login/signup/splash once you get into the application and for accessing Tabs and Drawer inside stack/switch, you can wrap the Drawer inside your top level navigator and tab inside the drawer.
So you root navigation would look like this.
export default RootNavigation = createSwitchNavigator({
LoginScreen: {screen: LoginContainer},
Application: {screen: AppDrawer},
});
Your drawer navigator should be like the following:
const AppDrawer = createDrawerNavigator({
ApplicationTab: {screen: TabBar},
... other screen that you might want to use in drawer navigation.
}, {
contentComponent : (props) => <MyCustomDrawer {...props} />
});
and, Tab Navigator would be,
const TabBar = createBottomTabNavigator({
TabScreen1: {screen: Tab1},
... other tabs...
}, {
tabBarComponent : (props) => <MyTabBar {...props} />
});
If you put each of those navigators in single file then please do declare Tab before Drawer and Drawer before the Switch, else it would give errors.
In my experience, customising drawer navigator is very simple and fruitful but customising tab is not, there aren't proper API doc for the same and community answers are also somewhat misleading.
BUT, with normal use cases and for most of the vivid ones too, you can do your job without needing to override the default one as it is already highly operable and customisable in terms of icons, materialism and each tab exposes its on onPress that can also be easily overriden.
and as you as the drawer is not getting operated from/via the header, then can you please ensure that the navigation prop you are using to operate the drawer open close or toggle action is the one given by drawer ?

How to organize navigation structure in React Native?

I'm using react-navigation library. Currently the navigation is organized in this way:
App.js:
const Layout = createRootNavigator(signedIn);
return (
<AppFontLoader>
<Layout />
</AppFontLoader>
);
AppNavigator:
export const createRootNavigator = (signedIn = false) => {
return createSwitchNavigator(
{
SignedIn: {
screen: SignedIn
},
SignedOut: {
screen: SignedOut
}
},
{
initialRouteName: signedIn ? "SignedIn" : "SignedOut"
}
);
};
AppNavigator:
export const SignedIn = createMaterialBottomTabNavigator(
{
MeetingsScreen: {
...
}
MeetingsScreen:
const MeetingNavigator = createStackNavigator({
MeetingsListScreen: {
screen: MeetingsListScreen,
navigationOptions: {
}
},
AddMeetingForm: {
screen: AddMeetingFormScreen
},
MeetingScreen: {
screen: MeetingScreen
}
}, {initialRouteName: "MeetingsListScreen"});
The error is shown with the current structure:
You should only render one navigator explicitly in your app, and other navigators should by rendered by including them in that navigator.
Apparently, I shouldn't nest one navigator into another, but I'm struggling to come up with the right navigation structure.
How to organize the navigation so that I can have more layers of navigation to move between screens?
I've encountered the same issue, so what I ended up doing was just making one navigation. Rootstack. All routes are there. My app.js has only root stack and navigations.

Call child react navigation prop from super component in react-native / react-navigation

I have a react native application using react navigation. I have following structure in my application.
class MainContainer extends Component {
render() {
return (
<View style={{ flex: 1 }}>
<Header
backgroundColor={appcolors.primaryColor}
leftComponent={<TouchableOpacity onPress={() => this.props.navigation.toggleDrawer() }><Feather name='align-justify' size={24} color='white' /></TouchableOpacity>}
centerComponent={{ text: this.props.headerTitle , style: { color: 'white' } }}
/>
<MainDrawerNavigation/>
</View>
);
}
};
and <MainDrawerNavigation/> is a react navigation component as follows.
MainDrawerNavigation = createDrawerNavigator({
XScreen: {
screen: XScreen,
},
YScreen: {
screen: YScreen,
},
ZScreen: {
screen: ZScreen,
},
},{
}
});
I have got error when trying to call this.props.navigation.toggleDrawer() from MainContainer. Then for testing purpose I have add a button to XScreen and tried to toggle drawer and it was success. So I want to know is there any way to pass child navigation props to super view. So I could call this.props.navigation.toggleDrawer() method and control drawer from MainContainer. or any navigation practices that can be use to solve this.
PS: the error I got is _this2.props.navigation.toggleDrawer is not a function
In MainContainer, the this.props.navigation is not initiated, so you got such error. You can only access it inside the child component of MainDrawerNavigation i.e. XScreen, YScreen & ZScreen only.
For best practices you need to design how all component will navigate into your app and pass Navigator objects/components as root component.
There are multiple navigators, you will can read them react navigation api doc.
A simplified app needs SwitchNavigator, DrawerNavigator, TabBarNavigator & StackNavigator.
SwitchNavigator :
It is used for user authentication. It will give control to toggle between two component (FYI, component can be a Navigator or React.Component).
export const AuthNavigator = SwitchNavigator(
{
AuthLoading: { screen: AuthLoadingScreen },
App: { screen: AppDrawer},
Auth: { screen: AuthStack}
},
{
initialRouteName: 'AuthLoading',
}
);
for more details
DrawerNavigator :
It is used to display side panel or sliding view at left or right side of the screen. So, you can directly pass this component to SwitchNavigator's authentication successful screen.
export default const AppDrawer = DrawerNavigator(
{
Home: { screen: TabBarNav },
Notes: { screen: NotesStack },
Invite: { screen: InviteContactsStack },
Files: { screen: FilesStack },
Settings: { screen: SettingsStack }
},
{
initialRouteName: "Home",
contentOptions: {
activeTintColor: "#e91e63"
},
contentComponent: props => <LeftSidePanel {...props} />
}
);
TabBarNavigator :
It is used to display tab bar at bottom for iOS and at top for android by default. This can be customized.
export default const TabBarNav = TabNavigator(
{
ChatsTab: {
screen: ChatsStack,
navigationOptions: {
tabBarLabel: "Chats"
}
},
InviteContacts: {
screen: InviteContactsStack,
navigationOptions: {
tabBarLabel: "Invite"
}
},
Notifications: {
screen: NotificationsStack,
navigationOptions: {
tabBarLabel: "Notifications"
}
},
Tasks: {
screen: TasksStack,
navigationOptions: {
tabBarLabel: "Tasks"
}
}
},
{
tabBarPosition: "bottom",
}
);
StackNavigator :
It's name suggests that it will hold a stack of component. So, when any item is selected from drawer, you can directly put a StackNavigator in that screen.
export default const ChatsStack = StackNavigator({
Chats: {
screen: Chats
},
Messages: {
screen: Messages
}
});
You can read Spencer Carli's blog on medium which explain with code.
Please let me know whether it satisfies your need.

React Native Navigation Drawer - Open page not in drawer

I am new to React Native development, so sorry if this seems obvious.
I have a new app that uses React Navigation Drawer as its main method of navigation. How can I have an onPress function within a page that navigates to a component that is not in my Navigation Drawer?
this.props.navigation.navigate('example') only seems to work for pages defined in the drawer.
My Drawer config:
const MyApp = createDrawerNavigator({
Interactive: {
screen: (props) => <Interactive {...props}
list={[
{ name: "First" },
{ name: "Second" },
{ name: "Third" },
{ name: "Fourth" },
{ name: "Fifth" },
{ name: "Sixth" },
{ name: "Seventh" },
{ name: "Eighth" },
]} />,
},
Settings: {
screen: SettingsScreen,
},
},
I am pressing a button within "Interactive" that should navigate to a component that is not include in the config above.
You can have multiple navigators inside your application (and usually this is the case), and actually every screen you want to navigate to should be defined inside a navigator. Every key in a navigator can be a single Screen or another navigator (Stack-, Drawer-, Tab- or SwitchNavigator).
const DrawerRoutes = createDrawerNavigator({
// your drawer navigator implementation ...
});
const MyApp = createSwitchNavigator(
{
Drawer: DrawerRoutes,
Example: YourScreen, // this would be the screen you want to navigator to
},
{
initialRouteName: 'Drawer'
}
);
And now you can navigate to YourScreen by simply calling this.props.navigation.navigate('Example') from within your Drawer.
In a react-navigation application it is not unusual to have a large combination of nested navigators, but there is always one root navigator.