onPress event on headerLeft under navigation.setOptions is not working - react-native

onPress event on headerLeft under navigation.options is not working it is still performing default functionality not overriding my onPress functionality for this. When I am clicking on back button it is moving to some random page not the previous page from which I am coming, so that's why I am trying to modify default functionality but it is not picking my onPress function.
useLayoutEffect(() => {
navigation.setOptions({
headerLeft: () => <Text onPress={()=>{console.log('back');}}>Back</Text>,
headerRight: () => <DetailsHeader isFavorite={detail.FVT_YN === "Y"} onSharePress={() => _onSharePress(detail)} onFavoritePress={() => _onFavoritePress(detail)} />,
});
}, [navigation, detail]);
In my app there are multiple bottom navigation tabs are there, so if I remove all other tabs and only keep one home tab then it is working fine, but when multiple tabs are there then back button move to any other tab page.
I have tried several ways but none of them working, so please help me find out the solution of this.

Try this:
useLayoutEffect(() => {
navigation.setOptions({
headerLeft: () => <Pressable onPress={()=>{console.log('back');}}><Text>Back</Text></Pressable>,
headerRight: () => <DetailsHeader isFavorite={detail.FVT_YN === "Y"} onSharePress={() => _onSharePress(detail)} onFavoritePress={() => _onFavoritePress(detail)} />,
});
}, [navigation, detail]);

Related

React Navigation HeaderLeft can't access Screen State

Tech stack: Expo, React Native, React Navigation
I created a basic Edit Profile screen for a user in my app and noticed that when I called an onPress function from the HeaderLeft/Right of that page to save the changes, the updated user fields tracked in state and set from a TextInput weren't being updated properly in the onPress function. Eventually I solved the issue by putting a button on the page to call the function which updated the user fields instead of calling the same function in the headers, but I don't understand why this wasn't working and how might it work.
Below are the important code snippets. Thank you! also looks similar to: React Navigation - access state inside setOptions() headerRight callback
EditProfileScreen
const { user, setUser } = useContext(AuthContext);
const [firstName, setFirstName] = useState(user?.firstName ?? "");
const [lastName, setLastName] = useState(user?.lastName ?? "");
useEffect(() => {
navigation.setOptions({
headerLeft: () => (
<Pressable onPress={() => navigation.goBack()}>
<Text>Cancel</Text>
</Pressable>
),
headerRight: () => (
<Pressable onPress={() => saveProfile()}>
<Text>Save</Text>
</Pressable>
),
});
}, [navigation]);
const saveProfile = () => {
console.log("first name user", user.firstName);
console.log("first name ", firstName); // why is this empty?????
console.log("last name user", user.lastName);
console.log("last name ", lastName);
}
<TextInput
style={styles.input}
maxLength={25}
activeUnderlineColor="grey"
placeholder=""
value={firstName}
onChangeText={(newFirstName) => setFirstName(newFirstName)} // i also tried onChangeText={setFirstName}
/>

How to hide top navigation bar in react-native?

I want to hide top navigation bar in some cases.
this is not work in reactnavigation V4
const RemoveTopBar = () => {
navigation.setOptions({
headerShown: () => false,
});
}
how can i handle this ?
Try to set like this.
navigation.setParams({ headerShown: false })}
you can check options in react navigation with respect to any version by selecting version from here

How to implement a shared Search Bar input across stack/tab navigators using react-navigation?

Snapchat's UI is currently setup with a floating SearchBar header that appears to be shared across a few screens/tabs. I'd like to replicate the shared SearchBar header using react-navigation. I currently have a half working solution...
Currently even though I have the headerTitle set on the StackNavigator, it appears that the header is rendering a brand new SearchBar (you can see the slight flicker indicating its rendering) upon navigation to the search results screen.
Here is the setup I have currently for one of the Stacks inside my TabNavigator.
function NetworkStack({ route, navigation }) {
return (
<Network.Navigator
initialRouteName="NetworkEventList"
screenOptions={({ navigation, route }) => ({
headerTitle: () => <Search navigation={navigation} route={route} stackName={"NetworkStack"}/>,
})}>
<Network.Screen
name="NetworkSearchResults"
component={SearchResults}
options={({ navigation, route }) => ({
//headerTitle: () => <Search navigation={navigation} route={route} focused={true} stackName={"NetworkStack"}/>,
headerBackImage: () => <BackButton navigation={navigation} shouldPop={true}/>,
headerBackTitleVisible: false,
gestureEnabled: true
})}/>
<Network.Screen
name="NetworkEventList"
component={NetworkEventList}
options={({ navigation, route }) => ({
headerLeft: () => <ProfileSidebarButton navigation={navigation}/>,
//headerTitle: () => <Search navigation={navigation} focused={false} stackName={"NetworkStack"}/>,
headerRight: () => <CommunityButton navigation={navigation} stackName={"NetworkStack"}/>
})}/>
</Network.Navigator>
)
}
Below is my TabNavigator.
function TabNavigator({ navigation, route }) {
return (
<Tab.Navigator
initialRouteName="NetworkStack"
tabBar={props => <TabBar {...props}/>}>
<Tab.Screen
name="CheckInStack"
component={CheckInStack}/>
<Tab.Screen
name="NetworkStack"
component={NetworkStack}/>
<Tab.Screen
name="MapStack"
component={MapStack}/>
</Tab.Navigator>
);
}
The logic that navigates to the search results component is inside the onFocus listener of the input. Here is the code for that...
const searchBarFocus = () => {
switch(props.stackName) {
case "MapStack":
var searchType = props.searchGoogle ? "AddEstablishment" : "ViewingEstablishments";
props.navigation.navigate('MapSearchResults', {searchType: searchType});
break;
case "NetworkStack":
props.addingMarkers(false);
var searchType = props.searchForPosting ? "ViewingEstablishments" : "ViewingUsers";
let index = null;
let routeState = props.route.state;
if(routeState) index = routeState.index;
if(index !== 1) {
console.log(props.navigation);
props.navigation.navigate('NetworkSearchResults', {searchType: searchType});
}
break;
case "CheckInStack":
props.addingMarkers(false);
props.navigation.navigate('CheckInSearchResults', {searchType: "ViewingUsers"});
break;
}
}
How would I go about configuring my navigation elements so that I have a singular SearchBar element that mounts one time? You can see in the gif I uploaded that the searchbar also loses focus upon navigation, this is also due to the second rendering/mounting of my Search component. Any suggestions would be much appreciated!
I was able to find a solution to my question. Feel free to comment or supply a better answer. I use the react-native-elements Search Bar to create my searching/input element at the header of my navigation stacks. Originally this was a View wrapping the SearchBar component. I changed this to a TouchableOpacity so that I could listen for onPress event. This is the new element I constructed. I kept the original navigation configuration that was supplied in the question.
return (
<TouchableOpacity style={[styles.mainContainer, {width: SEARCH_BAR_WIDTH_UNFOCUSED}]} onPress={() => searchBarPress()}>
<SearchBar
id={"searchBar-"+ props.stackName}
platform="ios"
ref={search => searchRef = search}
value={searchInput}
containerStyle={styles.searchInputContainerWrapper}
inputContainerStyle={styles.searchInputContainer}
inputStyle={{color: styles.inputContainer.color}}
round={true}
autoFocus={props.route.params ? true : false}
pointerEvents={props.route.params ? "auto" : "none"}
cancelButtonTitle="Cancel"
cancelButtonProps={{color: '#707070'}}
onChangeText={updateSearch}
//onFocus={searchBarFocus}
onCancel={() => console.log("Cancel")}
/>
</TouchableOpacity>
)
The key parts of creating the snapchat like search bar header is the autoFocus and pointerEvents properties. The property values needs to be dependent upon which screen the user is currently on.
I think, the good way is to create just a separate component with intention to be a searching component, then when searching happens the results is stored on the global state, as context or redux store
//search.js
const SearchBar = (props) => {...}; //which have access to the global state
//then on your routes
function StackScreen() {
return (
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{
headerTitle: props => <LogoTitle {...props} />,
headerRight: () => (
<SearchBar/>
),
}}
/>
<Stack.Screen
name="Users"
component={UsersScreen}
options={{
headerTitle: props => <LogoTitle {...props} />,
headerRight: () => (
<SearchBar/>
),
}}
/>
</Stack.Navigator>
);
}

React Navigation v.5 Tab Bar Icon Navigate to Modal

Anyone know a good alternative to tabBarOnPress in react navigation v.5? I want to navigate to a modal stack when a user presses a tabIcon, (i.e. cancel its default navigation behavior) but the icon seems to navigate to the Tab Screen first, then navigates to the modal.
For clarification, here is my PostIcon TabIcon Component
export const PostStackIcon: React.FC<TabBarIconProps> = ({ size, color }) => {
const navigation = useNavigation();
const goToCreatePost = () => {
navigation.navigate('CreatePostStack', { screen: 'CreatePost'});
}
return (
<TouchableWithoutFeedback onPress={() => goToCreatePost()}>
<Icon
name="Post"
width={size * 2}
height={size}
fillOpacity={0}
stroke={color}
secondaryStroke={color}
/>
</TouchableWithoutFeedback>
)
}
Official document
You can use listeners prop of Tab.Screen, this is the closest alternative to tabBarOnPress IMHO.
Below is quoted from the documents:
Sometimes you might want to add a listener from the component where you defined the navigator rather than inside the screen. You can use the listeners prop on the Screen component to add listeners. The listeners prop takes an object with the event names as keys and the listener callbacks as values.
Example:
<Tabs.Screen
name="Chat"
component={Chat}
listeners={{
tabPress: e => {
// Prevent default action
e.preventDefault();
},
}}
/>
You can also pass a callback which returns the object with listeners. It'll receive navigation and route as the arguments.
Example:
<Tabs.Screen
name="Chat"
component={Chat}
listeners={({ navigation, route }) => ({
tabPress: e => {
// Prevent default action
e.preventDefault();
// Do something with the `navigation` object
navigation.navigate('AnotherPlace');
},
})}
/>

React-Navigation HeaderRight onPress Handler throws error

i m trying to use react-navigation to implement an onPress handler which allows me to navigate to a screen called tasks
the below code shows the headerRight just fine. however, when i click on the headerRight button, i get the following error
"Undefined is not an object (evaluating _this2.props.navigation) on my expo simulator".
Anyone knows what could have gone wrong with my onPress handler? Tq
static navigationOptions = {
title: 'List',
headerRight: (
<Button
title='Add Task'
onPress={() => this.props.navigation.navigate('task')}
backgroundColor='rgba(0,0,0,0)'
color='rgba(0,122,255,1)'
/>)
}
I managed to get the codes working
hope this can help those using react-navigation and wanting to render a workable headerRight
static navigationOptions = ({navigation}) => ({
title: 'List',
headerRight: <Button
title= 'Add Task'
onPress={() => navigation.navigate('task')}
backgroundColor='rgba(0,0,0,0)'
color='rgba(0,122,255,1)'
/>
});