navigation.push not adding a new route - react-native

navigate works fine however when I replace it with push, it stops working.
<Text
onPress={() => {
//works
this.props.navigation.navigate("VideoPlayer", { id });
// doesn't work
this.props.navigation.push("VideoPlayer", { id });
}}
style={styles.text}
>
{title}
</Text>
How can I get push to work so I can remount components?
I am using a Drawer with a new stack for each route so I can use headers:
const config = {
initialRouteName: "Home",
contentOptions: {
activeTintColor: "#e91e63",
itemStyle: {
flexDirection: "row-reverse"
}
},
drawerWidth: 300,
drawerPosition: "right"
};
const withHeader = (
screen: Function,
routeName: string,
Header
): StackNavigator =>
createStackNavigator(
{
[routeName]: {
screen,
navigationOptions: ({ routeName, props }) => ({
header: props => <Header {...props} />
})
}
},
{
transparentCard: true
}
);
const routes = {
Home: {
screen: withHeader(HomeScreen, "Home", BasicHeader)
},
Links: {
screen: withHeader(LinksScreen, "Links", DrawerHeader)
},
Settings: {
screen: withHeader(SettingsScreen, "Settings", DrawerHeader)
},
VideoEpisodes: {
screen: withHeader(VideoEpisodesScreen, "Video Episodes", DrawerHeader)
},
VideoPlayer: {
screen: withHeader(VideoPlayerScreen, "Video Player", DrawerHeader)
},
TestYourself: {
screen: withHeader(TestYourselfScreen, "Test Yourself", DrawerHeader)
},
MyResults: {
screen: withHeader(MyResultsScreen, "My Results", DrawerHeader)
},
BookmarkedVideos: {
screen: withHeader(
BookmarkedVideosScreen,
"Bookmarked Videos",
DrawerHeader
)
},
Search: {
screen: withHeader(SearchScreen, "Search", DrawerHeader)
},
About: {
screen: withHeader(AboutScreen, "About", DrawerHeader)
}
};
const AppNavigator = createDrawerNavigator(routes, config);
export default createAppContainer(AppNavigator);

.push() is a StackAction method, you have to use a stackNavigator in order to use it

Related

I have a problem in my code when updating react-navigation v2 to v3

I want to update the react-navigation library V2 to V3 and change part of my code thinking that there would not be any problems but it turns out that I have problems creating createStackNavigator with a screen of type createDrawerNavigator and that in turn contains createBottomTabNavigator.
my code that works with the previous version was:
export const createRootNavigator = (signedIn = false) => {
const commonNavigationOptions = {
headerStyle: {
shadowColor: 'transparent',
elevation: 0
},
headerTintColor: DEFAULT_THEME.topaz
};
const SignedIn = createStackNavigator(
{
Home: {
screen: Drawer('Home'),
navigationOptions: () => ({
headerStyle: {
height: 0
},
header: getSafeArea(DEFAULT_THEME.backgrouncolorHomeSafeArea)
})
},
Cards: {
screen: Tabs('Cards'),
navigationOptions: () => ({
headerStyle: {
height: 0
}
})
},
);
const SignedOut = createStackNavigator(
{
SignIn: {
screen: LoginContainer,
navigationOptions: () => ({
headerStyle: {
height: 0
},
header: getSafeArea(DEFAULT_THEME.dark)
})
},
SelectableCardsList: { screen: SelectableCardsListComponent },
);
return createSwitchNavigator(
{
SignedIn: { screen: SignedIn },
SignedOut: { screen: SignedOut }
},
{
initialRouteName: signedIn ? 'SignedIn' : 'SignedOut'
}
);
};
const Drawer = (initialRoute) => createDrawerNavigator(
{
Home: { screen: Tabs('Home') },
{
initialRouteName: initialRoute,
contentComponent: CustomDrawerComponent
}
);
const Tabs = (initialRouteName) => createBottomTabNavigator(
{
Home: {
screen: HomeContainer,
navigationOptions: {
tabBarLabel: I18n.t('tabs.me')
}
},
Home2: {
screen: Home2,
navigationOptions: {
tabBarLabel: I18n.t('tabs.credentials')
}
},
{
initialRouteName: initialRouteName,
tabBarComponent: ({ navigation }) => <CustomBottomBarComponent navigation={navigation} navigationState={navigation['state']} />,
tabBarOptions: {
style: {
backgroundColor: 'white'
}
}
}
);
try this solution with react-navigation V3 and send me an error
I try the following:
encapsulate createSwitchNavigator in createAppContainer and separate (SignedOut and SignedOut) createStackNavigator out of createSwitchNavigator, the rest is still the same.
export const createRootNavigator = (signedIn = false) => createAppContainer(createSwitchNavigator(
{
SignedIn: { screen: SignedIn },
SignedOut: { screen: SignedOut }
},
{
initialRouteName: signedIn ? 'SignedIn' : 'SignedOut'
}
));
I get the following error: The component for route 'Home' must be a react component. For Example
import MyScreen from './MyScreen';
...
Home : MyScreen,
}
you can also use a navigator:
The problem is located in this part:
const SignedIn = createStackNavigator(
{
Home: {
screen: Drawer,
Also try to change Drawer for any component (a component with a blank screen) and this works, but I can not insert the Tabs in the Drawer.
Thank you very much for your help.

Modal navigation for certain screens in react-native app

For 3 screens in my app I need to make a modal transition.
For the rest of the screens - I need the default right-to-left transition.
How do I achieve this with different stack navigators?
const AuthStack = createStackNavigator(
{
LogIn: { screen: LogInScreen },
Signup: { screen: SingupScreen },
Welcome: { screen: WelcomeScreen },
CodeVerification: { screen: CodeVerificationScreen },
PasswordSelection: { screen: PasswordSelectionScreen },
RegistrationSuccess: { screen: RegistrationSuccessScreen }
},
{
initialRouteName: 'LogIn'
}
)
const ModalNavigator = createStackNavigator({
ContactInfoEdit: { screen: ContactInfoEditScreen },
DeliveryAddressEdit: { screen: DeliveryAddressEditScreen },
OrderPlacedScreen: { screen: OrderPlacedScreen },
},
{
initialRouteName: 'ContactInfoEdit',
})
const ProductsStack = createStackNavigator(
{
Products: {
screen: ProductsScreen
},
Product: {
screen: ProductScreen
},
ProductBuy: {
screen: ProductBuyScreen
},
OrderConfirm: {
screen: OrderConfirmScreen
},
PlaceOrder: {
screen: PlaceOrderScreen
},
Modal: ModalNavigator
},
{
initialRouteName: 'Products',
mode: 'modal',
}
)
If I set mode: modal it will make all the navigation animations will be modal.
If I remove it, all the navigations will be default (right-to-left)
const ProductsTabStack = createBottomTabNavigator(
{
Orders: { screen: OrdersScreen },
Products: { screen: ProductsStack },
Profile: { screen: ProfileScreen }
},
{
initialRouteName: 'Products',
backBehavior: 'none',
tabBarOptions: {
activeTintColor: '#ffffff',
inactiveTintColor: primaryColor,
activeBackgroundColor: primaryColor,
labelStyle: {
marginBottom: 17,
fontSize: 15,
},
tabStyle: {
shadowColor: primaryColor,
borderWidth: 0.5,
borderColor: primaryColor,
},
},
},
)
export const AppNavigator = createSwitchNavigator({
Auth: AuthStack,
Categories: ProductsTabStack
})
I tried setting mode: modal in the ModalNavigator, but then it took the default parent navigation.
You probably want to try to use StackNavigatorConfig while navigating to that screen this.props.navigation.navigate('ScreenName', params, {mode: 'modal'})
If you want to keep all your transition code in same file as you have right now, you can do the same as what react-navigation is suggesting here
It goes something like that
import { createStackNavigator, StackViewTransitionConfigs } from 'react- navigation';
/* The screens you add to IOS_MODAL_ROUTES will have the modal transition. */
const IOS_MODAL_ROUTES = ['OptionsScreen'];
let dynamicModalTransition = (transitionProps, prevTransitionProps) => {
const isModal = IOS_MODAL_ROUTES.some(
screenName =>
screenName === transitionProps.scene.route.routeName ||
(prevTransitionProps && screenName ===
prevTransitionProps.scene.route.routeName)
)
return StackViewTransitionConfigs.defaultTransitionConfig(
transitionProps,
prevTransitionProps,
isModal
);
};
const HomeStack = createStackNavigator(
{ DetailScreen, HomeScreen, OptionsScreen },
{ initialRouteName: 'HomeScreen', transitionConfig: dynamicModalTransition }
);
OK, found a workaround for custom transitions in 1 StackNavigator using https://www.npmjs.com/package/react-navigation-transitions:
const handleCustomTransition = ({ scenes }) => {
const nextScene = scenes[scenes.length - 1]
if (nextScene.route.routeName === 'ContactInfoEdit')
return fromBottom()
else
return fromRight()
}
const ProductsStack = createStackNavigator(
{
Products: {
screen: ProductsScreen
},
Product: {
screen: ProductScreen
},
ProductBuy: {
screen: ProductBuyScreen
},
OrderConfirm: {
screen: OrderConfirmScreen
},
PlaceOrder: {
screen: PlaceOrderScreen
},
ContactInfoEdit: { screen: ContactInfoEditScreen },
DeliveryAddressEdit: { screen: DeliveryAddressEditScreen },
OrderPlacedScreen: { screen: OrderPlacedScreen },
},
{
initialRouteName: 'Products',
transitionConfig: (nav) => handleCustomTransition(nav)
}
)

React-navigation drawer is routing me back to previous screen immediately after rendering item screen

I have a StackNavigation like this:
const AppNavigator = createStackNavigator({
Login: {
screen: Login,
navigationOptions: () => ({
title: 'Login',
headerTintColor: 'white',
headerStyle:{
backgroundColor: '#000',
elevation: 0,
showdowOpacity: 0
},
})
},
Home: {
screen: AppDrawerNavigator,
navigationOptions: () => ({
header: null
})
},
});
With a DrawerNavigator nested inside:
const AppDrawerNavigator = createDrawerNavigator({
Home: {
screen: Home,
navigationOptions: {
drawerLabel: 'Home',
gesturesEnabled: false,
}
},
Favorites: {
screen: Favorites,
navigationOptions: {
drawerLabel: 'Favorites',
}
}
},
{
drawerPosition: 'left',
contentComponent: props => <Drawer {...props} />
});
The initial route of the stack navigator is working fine
Login -> Home
But when I try navigating from Home to Favorites it navigates immediately back to Home after rendering the Favorites screen.
I am using react-navigation#2.11.2 and react-native#0.56.0
With Home being used in both stack and drawer navigator.
There are high chances of name conflicts occurring here.
Try this structure.
const Stack = {
FirstView: {
screen: FirstView
},
SecondView: {
screen: SecondView
},
ThirdView: {
screen: ThirdView
}
};
const DrawerRoutes = {
FirstViewStack: {
name: 'FirstViewStack',
screen: StackNavigator(Stack, { initialRouteName: 'FirstView' })
},
SecondViewStack: {
name: 'SecondViewStack',
screen: StackNavigator(Stack, { initialRouteName: 'SecondView' })
},
ThirdViewStack: {
name: 'ThirdViewStack',
screen: StackNavigator(Stack, { initialRouteName: 'ThirdView' })
},
};
const RootNavigator =
StackNavigator({
Drawer: {
name: 'Drawer',
screen: DrawerNavigator(
DrawerRoutes,
),
},
...Stack
},
{
headerMode: 'none'
}
);
I faced a similar issue when i tried to use a hamburger menu in my Home page (which uses stack navigator to goto other pages).
Check this Git Article also.

How can I change the header navigation title dynamically when switcing tabs

I have 2 tabs and I put inside in createStackNavigator
I am using
"react-navigation": "^2.0.1",
"react-native": "0.55.3",
const Cstack = createStackNavigator({
cstack: {
screen: Screen1,
}
},{
headerMode:'none'
});
const Dstack = createStackNavigator({
dstack: {
screen: Screen2,
},
},{
headerMode:'none'
});
const mytabnavigator= createTabNavigator({
Tab1: {
screen: Cstack,
navigationOptions: ({navigation}) => ({
headerTintColor: 'white',
tabBarIcon: ({focused, tintColor}) => {
return (
<IconIonicons
name='ios-cash'
type='ionicon'
color="#FFFFFF"
size={26}
/>
);
},
})
},
Tab2: {
screen: Dstack,
navigationOptions: ({navigation}) => ({
headerTintColor: 'white',
tabBarIcon: ({focused, tintColor}) => {
return (
<IconIonicons
name='ios-card'
type='ionicon'
color="#FFFFFF"
size={26}
/>
);
},
})
}
}, {
tabBarOptions: {
showIcon: true,
style: {
backgroundColor: '#3f51b5',
},
inactiveTintColor: '#FFFFFF',
activeTintColor: "#FFFFFF"
},
});
const StackTab = createStackNavigator({
stacktab: mytabnavigator,
navigationOptions: ({navigation}) => ({
title: 'Welcome'
})
});
My problem is that they both share the same title Welcome
how can I dynamically change the title when I switch to other tab example I will switch tabsettings then my title would be Settings.
If you are using react navigation <2 i.e ~1.5.* You can set it like this.
const Tabs = TabNavigator({
Tab1:{
screen: Tab1,
navigationOptions: ({navigation}) => {
return { title: "Tab 1 Heading", tabBarLabel:"Tab 1 "}
},
}
Tab2:{
screen: Tab2
navigationOptions: ({navigation}) => {
return { title: "Tab 2 Heading", tabBarLabel:"Tab 2 "}
}
}
})
const Stack = StackNavigator({
tabs: {
screen: Tabs
navigationOptions: ({navigation}) => {
return { title: "Stack"}
}
},
otherScreen: Page
})
I'm not sure why did they remove this feature, when you try the same it won't work on the latest react-navigation. Now title object key is used for fallback it seems.
This may be helpful some users. If you wish you can try downgrading also.
I have the Upgraded the React Navigation to latest today for my project I think this way will be useful to someone
const Tabs = TabNavigator({
Tab1:{
screen: Tab1,
navigationOptions: ({navigation}) => {
return { tabBarLabel:"Tab 1 "}
}},
Tab2:{
screen: Tab2
navigationOptions: ({navigation}) => {
return { tabBarLabel:"Tab 2 "}
}}
});
Tabs.navigationOptions = ({navigation})=>{
const { routeName } = navigation.state.routes[navigation.state.index]; //This gives current route
switch(routeName){
case "Tab1":
headerTitle="Tab 1";
break;
case "Tab1":
headerTitle="Tab 1";
break;
}
return {
headerTitle: headerTitle
}
}
I had the same problem and I couldn't find anything but think I may have figured out a solution.
I added a navigationOptions callback for the screen -
const RootStack = createStackNavigator({
HomeScreen: {
screen: CustomHome,
navigationOptions: ({navigation}) => {
if(navigation && navigation.state && navigation.state.params && navigation.state.params.title) {
return {title: navigation.state.params.title}
}
}
},
InputScreen: {
screen: CustomInput,
navigationOptions: ({navigation}) => {
return {title: navigation.state.params.title}
}
}
})
and in my components in the constructor, I am calling this to update the header name
props.navigation.setParams({title: props.navigation.state.params.input.name})
Hope this helps.
You can set the header title manually in every single screen by making use of navigationOptions. Example:
class TabSettingsScreen extends React.Component {
static navigationOptions = ({navigation}) => ({
title: 'Settings'
})
render() {
return (... );
}
}
remove headerModer: 'none' in child navigators and give required title for screens
const Tstack = createStackNavigator({
tabsettings: {
screen: tabsettings,
navigationOptions: {title : 'Settings'}
},
});
Remove title in mainStackNavigator
const StackTab = createStackNavigator(
{
stacktab: mytabnavigator
},
{
navigationOptions: {
header: null
}
}
);
use TabNavigator
import TabNavigator from 'react-navigation';
declare title for each pages separately
class Screen1 extends React.Component {
static navigationOptions = ({navigation}) => ({
title: 'Settings'
})
}
remove headerMode:'none'

How to disable Drawer in nested component in React Navigation

Consider the render of the Main component:
render() {
const { isAuthenticated } = this.props;
return (
<View>
{isAuthenticated ? <Dashboard /> : <Login />}
</View>
);
I want to lock the drawer in the Login component. Now i know that i could achieve this if Login wasn't a child of Main this way (in my Router component):
Login: {
screen: Login,
navigationOptions: () => ({
drawerLockMode: 'locked-closed',
}),
},
But since Login is a child of Main and Main has the drawer, Login will automatically have the drawer too. I've tried "overriding" it by calling this in Login:
static navigationOptions = {
drawerLockMode: 'locked-closed',
};
But no success. Here's my Router:
const Stack = {
Main: { screen: Main },
Login: {
screen: Login,
navigationOptions: () => ({
drawerLockMode: 'locked-closed',
}),
},
Outbox: { screen: Outbox },
Dashboard: { screen: Dashboard },
JobList: { screen: JobList },
CreateJob: { screen: CreateJob },
Reporting: { screen: Reporting },
JobDescription: { screen: JobDescription },
};
const DrawerRoutes = {
DrawerStack: {
name: 'DrawerStack',
screen: StackNavigator(
Stack,
{
initialRouteName: C.MAIN,
headerMode: 'none',
navigationOptions: {
gesturesEnabled: false,
},
}),
},
};
export const DrawerNavigation = StackNavigator({
Drawer: {
name: 'Drawer',
screen: DrawerNavigator(DrawerRoutes, {
contentComponent: DrawerPanel,
}),
},
...Stack,
}, { headerMode: 'none' });
Is there a way to achieve this ?