Is it possible to pass the goBack() function as a parameter - react-native

I have a function AccountScreen. From this screen I would like to be able to navigate.goBack(). I tried following the guide here on how to go back to a previous screen but I am getting an error.
Here is my code:
AccountScreen.js
const BackButton = styled.Button`
`;
function AccountScreen({doThis}) {
return(
<Root>
<BackButton title="" onPress={() => doThis} />
<Text>Account</Text>
</Root>
)
};
export default AccountScreen;
navigations.js
const createProfileDrawer = ({navigation}) =>
<Drawer.Navigator>
<Drawer.Screen name="Profile" component={ProfileScreen}/>
<Drawer.Screen name="Account"
component={AccountScreen(navigation.goBack())} />
</Drawer.Navigator>
So when I try and pass it like this I get an error The action 'GO_BACK' was not handled by any navigator. Is it possible to pass a function like this?

Try making the following changes:
in AccountScreen.js:
import { useNavigation } from '#react-navigation/native';
function AccountScreen() {
const navigation = useNavigation();
return(
<Root>
<BackButton title="" onPress={() => navigation.openDrawer()} />
in navigations.js:
<Drawer.Screen name="Account" component={AccountScreen} />
Note that action you want is likely not 'goBack' but 'openDrawer'.

Related

React Native navigation 6 (Expo) - how can I toggle the drawer tab from the header of my Tabs navigation?

Hi I have react native (using expo) navigation 6. I am trying to have Tabs (Bottom) navigation and drawer navigation. I want to have the drawer nav hamburger menu inside the header. As far as I can see its being done having the following
headerLeft: (props) => {
return <Button
title="yes"
onPress={() => navigation.toggleDrawer() } />
}
either inside screenOptions or options (of the Tabs navigation). I kept it in screenOptions as I want it to be visible on all screens. However whatever I tried so far I am always getting an err saying either
undefined is not an object (wenn I pass in an object to screenOption (please see full code below)
or
navigation.ToggleDrawer is not a function - when I pass a function to screenOptions (please see full code below). I cannot find any solution or understand what I am doing wrong. Any help would be great!
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
return (
<Drawer.Navigator>
<Drawer.Screen name="Test" component={Test} />
<Drawer.Screen name="s" component={SearchScreen} />
</Drawer.Navigator>
)
}
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator
screenOptions={({ navigation }) => ({ //here I get "undefined is not an object"
headerLeft: (props) => {
return <Button
title="yes"
onPress={() => navigation.toggleDrawer() } />
}
})}
/*screenOptions={{ // here I would get "navigation.ToggleDrawer is not a function"
}}*/
>
<Tab.Screen name="Home" component={HomeScreen}/>
<Tab.Screen name="Tab1" component={Tab1} />
<Tab.Screen name="Tab2" component={Tab2} />
</Tab.Navigator>
);
}
const Navigator = () => {
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
)
}
export default Navigator;

How to pass props to a screen component in react navigation

I have a navigator that looks like this and I'm trying to pass informations to all the tabs below it.
import {createMaterialTopTabNavigator} from '#react-navigation/material-top-tabs';
const Tab = createMaterialTopTabNavigator();
<Tab.Navigator
swipeEnabled={false}
initialRouteName="TabMapScreen"
screenProps={user} // I've tried this
initialLayout={{width: Dimensions.get('window').width}}
>
<Tab.Screen
name="TabMapScreen"
component={PostsTab}
/>
<Tab.Screen
name="TabMapScreen"
component={() => <PostsTab props={user} />} // also tried this
/>
</Tab.Navigator>
what's the correct solution to passing props to a screen, straight from the navigator?
You can use the initialParams
<Tab.Screen
name="TabMapScreen"
component={PostsTab}
initialParams={{userData: user}} //User data is just an alias
/>
Just try this
<Tab.Screen name="TabMapScreen">
{props => <A123 {...props} props={user} />}
</Tab.Screen>
I think it is what you want !
There is two ways to do so:
Route params
This is if you need to change the props/parameters dynamically at navigate time:
function HomeScreen({ navigation }) {
return <View>
<Button
title="Go to Details"
onPress={() => {
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
}}
/>
</View>
}
function DetailsScreen({ route, navigation }) {
/* 2. Get the param */
const { itemId, otherParam } = route.params
...
}
Initial params
This way is if you need to pass props/params when the route is defined
<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{ itemId: 42 }}
/>
Full documentation here

UI Kitten and initialRouteName

I am trying to set a specific tab to start the application. UI kitten's navigation, starts up with the first tab, and actually I want the tab that is in the second position to be the first to appear to the user. I can not find how to set the initialRoute withtin UI kittens Bottom tab bars. I post some of my code so it can be clear:
const { Navigator, Screen } = createBottomTabNavigator();
const BottomTabBar = ({ navigation, state }) => (
<View>
<Divider />
<BottomNavigation
appearance="noIndicator"
selectedIndex={state.index}
onSelect={(index) => navigation.navigate(state.routeNames[index])}
>
<BottomNavigationTab title="screen1" icon={icon1} />
<BottomNavigationTab title="screen2" icon={icon2} />
<BottomNavigationTab title="screen3" icon={icon3} />
</BottomNavigation>
</View>
);
export const BottomTabsNavigator = () => (
<Navigator tabBar={(props) => <BottomTabBar {...props} />}>
<Screen name="screen1" component={Screen1}/>
<Screen name="screen2" component={Screen2}/>
<Screen name="screen3" component={Screen3} />
</Navigator>
);
export const AppNavigator = () => {
return (
<SafeAreaView>
<NavigationContainer>
<Navigator headerMode='none' >
<Screen name={'BottomTabs'} component={BottomTabsNavigator} />
</Navigator>
</NavigationContainer>
</SafeAreaView>
)
};
I've tried in multiple positions but it doesn't seem to work.
Within the following component:
<Navigator tabBar={(props) => <BottomTabBar {...props} />}>
You need to use the following prop: initialRouteName, like so:
<Navigator initialRouteName={'namehere'} tabBar={(props) => <BottomTabBar {...props} />}>
This is telling the navigator what screen to start on when initially rendered! Hope this helps.
For anyone outside of this question that has landed on this page, you can specify what screen you want the navigator to "start" on by using the prop: initialRouteName. This then tells the navigator to use this as your landing page!

React Native Tab nested into Stack navigation v5 - best practice to update header

I am trying to understand what's the best approach to nested React Native Navigation v5.
I have a TabNavigation nested into a Stack.Navigator as follow:
const MainNavigation = () => {
return (
<SafeAreaProvider>
<NavigationContainer>
<StatusBar barStyle="light-content" />
<Stack.Navigator screenOptions={navStackOptions} >
<FirstListStack.Screen name="FirstListStack" component={TabNavigation} options={FirstNavOpt} />
<FirstListStack.Screen name="AnotherView" component={AnotherView} options={AnotherViewNavOpt} />
<SecondListStack.Screen name="SecondListStack" component={TabNavigation} options={SecondNavOpt} />
<ThirdListStack.Screen name="ThirdListStack" component={TabNavigation} options={ThirdNavOpt} />
</Stack.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
function TabNavigation() {
return (
<Tab.Navigator
initialRouteName="TabOne"
>
<Tab.Screen name="TabOne" component={TabOne} options={navTabOptions} />
<Tab.Screen name="TabTwo" component={TabTwo} options={navTabOptions} />
<Tab.Screen name="TabThree" component={TabThree} options={navTabOptions} />
</Tab.Navigator>
);
}
};
export default MainNavigation;
Now, when switching between the tabs, the stack navigation header does not get updated.
What's the best approach to access the state of the Stack Navigation and update its state? In particular to update the header buttons?
Let me know if my question is unclear.
Many thanks.
I found a solution, but I am not sure is a good practice.
I changed the logic of the Navigation moving the Tab Nav as parent and the Stack Nav as child.
const Tab = createBottomTabNavigator();
const FirstListStack = createStackNavigator();
const SecondListStack = createStackNavigator();
const ThirdListStack = createStackNavigator();
const MainNavigation = () => {
const navTabOptions = ({ route }) => ({
tabBarVisible: isTabBarVisible(route)
});
return (
<SafeAreaProvider>
<NavigationContainer>
<StatusBar barStyle="light-content" />
<Tab.Navigator>
<Tab.Screen name="First" component={FirstListStackScreen} options={navTabOptions} />
<Tab.Screen name="Second" component={SecondListStackScreen} options={navTabOptions} />
<Tab.Screen name="Third" component={ThirdListStackScreen} options={navTabOptions} />
</Tab.Navigator>
</NavigationContainer>
</SafeAreaProvider>
);
function isTabBarVisible(route) {
// Check here if the route.state is not undefined
// and based on the route return true or false
// to show or hide the tab bar
}
function FirstListStackScreen() {
return (
<FirstListStack.Navigator>
<FirstListStack.Screen name="First" component={} />
</FirstListStack.Navigator>
);
}
function SecondListStackScreen() {
return (
<SecondListStack.Navigator>
<SecondListStack.Screen name="Second" component={} />
</SecondListStack.Navigator>
);
}
function ThirdListStackScreen() {
return (
<ThirdListStack.Navigator>
<ThirdListStack.Screen name="Third" component={} />
</ThirdListStack.Navigator>
);
}
};
export default MainNavigation;
Please post any better solution to this.
Thanks

How to create custom header options for each screen multi stack navigation react native?

I am looking for a way to set custom header options (styling, icons, enabling/disabling back button, left and right options for the header) for each of the screen in the stacks, while maintaining multi-stack architecture for my app in react native?
This is how my App.js looks right now, and I am willing to change it if need be.
const Stack = createStackNavigator();
const App = () => {
const ref = React.useRef();
const { getInitialState } = useLinking(ref, {
prefixes: ['FoodApp://'],
});
const AuthStack = createStackNavigator();
function AuthStackScreen() {
return (
<AuthStack.Navigator>
<AuthStack.Screen name="LogIn" component={LogIn} />
<AuthStack.Screen name="SignUp" component={SignUp} />
</AuthStack.Navigator>
);
}
const AppStack = createStackNavigator();
//I'd like to set different header options for each of the screen here
function AppStackScreen() {
return (
<AppStack.Navigator>
<AppStack.Screen name="MenuCategoryItems" component={MenuCategoryItems} />
<AppStack.Screen name="Delivery" component={Delivery} />
<AppStack.Screen name="Account" component={Account} />
<AppStack.Screen name="Notification" component={Notification} />
<AppStack.Screen name="Cart" component={Cart} />
</AppStack.Navigator>
);
}
//TODO: pass customized bar components
const Tab = createBottomTabNavigator();
//I'd like to set different header options for each of the screen here
function Tabs(){
return (
<Tab.Navigator tabBar={props => <BottomMenu {...props} />}>
<Tab.Screen name="Home" component={Home} />
<Tab.Screen name="Delivery" component={Delivery} />
<Tab.Screen name="Account" component={Account} />
<Tab.Screen name="Notification" component={Notification} />
<Tab.Screen name="Cart" component={Cart} />
</Tab.Navigator>
);
}
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={Tabs} />
<Stack.Screen name="AppStack" component={AppStackScreen} />
/*Should I place something else here so that I have access to both AppStack and Tabs navigations?*/
</Stack.Navigator>
</NavigationContainer>
);
};
export default App;
Not sure if this is what you need but here is how I customize some "borderColor" value for my header component.
You can pass any options you want via the setOptions method of the navigation component. It will be populated in the scene.descriptor.options parameter.
Below an example of how I am using it in my app.
the header options for my screen/navigator.
header: ({scene, previous, navigation}) => {
const {options} = scene.descriptor;
let borderColor = options.borderColor ?? 'yellow';
if (scene.route.name.startsWith('Test')) {
borderColor = 'blue';
}
return <HeaderBar options={options}
title={title}
previous={true}
navigation={navigation}
borderColor={borderColor}
/>;
}
And in any of the screens components I can use
useLayoutEffect(() => {
navigation.setOptions({
borderColor: 'orange'
})
}, [ navigation ])
Now, my <HeaderBar> component will receive a prop borderColor whose value is 'orange'.
export const HeaderBar = ({ options, title, previous, navigation, borderColor = 'yellow' }) => {
[...]
console.log(borderColor); // orange
}
As you can see, my HeaderBar component also receive the full options as a prop, therefore I could skip the borderColor prop and check the options inside the header component itself.
Like so
export const HeaderBar = ({ options, title, previous, navigation }) => {
const { borderColor } = options;
[...]
}
Hope it will help you if not too late.
Well. You could hide header default of react-navigation in your stack.
function AppStackScreen() {
return (
<AppStack.Navigator headerMode={'none'}>
<AppStack.Screen name="MenuCategoryItems" component={MenuCategoryItems} />
<AppStack.Screen name="Delivery" component={Delivery} />
<AppStack.Screen name="Account" component={Account} />
<AppStack.Screen name="Notification" component={Notification} />
<AppStack.Screen name="Cart" component={Cart} />
</AppStack.Navigator>
Then, you could custom header component and import it in each your screen.
Sorry because my EL. hope help U.