I get a problem to handle hardware back button android in React Native, I want to back in specific page/component when I press back button in hardware/device, but I always get error 'undefined is not an object (Evaluating 'this.props.navigation').
this is my script :
import { Platform, StyleSheet, Text, View, BackHandler } from 'react-native';
import { createStackNavigator, createAppContainer, NavigationActions, createBottomTabNavigator } from 'react-navigation';
import OnBoarding from './apps/src/onBoarding/OnBoarding';
import Welcome from './apps/src/welcome/Welcome';
import Login from './apps/src/login/Login';
const MainNavigator = createStackNavigator({
OnBoarding: OnBoarding,
Welcome: Welcome,
Login: Login
},{
initialRouteName: 'OnBoarding',
headerMode: 'none',
navigationOptions: {
headerVisible: false
}
});
const Approot = createAppContainer(MainNavigator);
var screen = '';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
routeName: ''
}
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton() {
if(screen == 'Login') {
this.props.navigation.navigate('OnBoarding');
}else{
return false;
}
}
getActiveRouteName(navigationState) {
if (!navigationState) {
return null;
}
const route = navigationState.routes[navigationState.index];
// dive into nested navigators
if (route.routes) {
return this.getActiveRouteName(route);
}
return route.routeName;
}
render() {
return <Approot onNavigationStateChange={(prevState, currentState) => {
screen = this.getActiveRouteName(currentState)
}} />;
}
}
in this case, I have 3 component, they are OnBoarding, Welcome, Login, when postion in Login I want to back to OnBoarding when press hardware back button, please help me to solve this problem.
Thanks.
You will have to use the navigation services as you want to navigate from outside of navigation (root of the app). you can follow documentation.
https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html
Related
I am currently transitioning from Wix RNN V1 to V2, and so far I've managed to find the appropriate replacement APIs, except for overriding the back button on Android.
In V1 we could pass the overrideBackPress: true attribute, and then handle back button presses manually on the cooresponding screen.
However, in V2 I've found no such replacement, and the only topics I could find were this thread:
https://github.com/wix/react-native-navigation/issues/4217
I've implemented the suggestions there, but Wix navigation is still automatically closing screens even though it should be overwritten.
Any known a solution for this?
I had the same issue and the only way i could override the backpress behavior on both platforms is to replace the left back button with custom button and use the BackHandler of react native for the hardware button in Android. The code is as below.
Component A
//Navigate to component B from A
Navigation.push(this.props.componentId, {
component: {
name: 'ComponentB',
options: {
topBar: {
leftButtons: [{
id: 'backPress',
text: 'Back',
icon: require('backbutton.png')
}]
},
}
}
});
Component B
import React, { PureComponent } from 'react';
import { View, BackHandler } from 'react-native';
import { Navigation } from 'react-native-navigation';
export default class ComponentB extends PureComponent {
constructor(props) {
super(props);
Navigation.events().bindComponent(this);
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
}
navigationButtonPressed({ buttonId }) {
switch (buttonId) {
case 'backPress': {
this.handleBackPress();
break;
}
}
}
handleBackPress = () => {
//Custom logic
//Go back if required
Navigation.pop(this.props.componentId)
//Stop the default navigation
return true;
};
//Render component
render() {
return (<View></View>);
}
}
You can use registerScreenPoppedListener:
Navigation.events().registerScreenPoppedListener((event) => {
if (event.componentId === "my-screen-id") {
// do something
}
});
Being a newbie in RN programming, I'm trying to handle android hardware button. But pressing it on screen leads to simultaneously going to previous screen and closing app.
My StackNavigator looks like:
const navigatorApp = StackNavigator({
Screen1: { screen: Screen1 },
Screen2: { screen: Screen2 },
Screen3: { screen: Screen3 },
Screen4: { screen: Screen4 }
})
I tried to make a global backpress handling for screens like
class HandleHavigation extends React.Component {
componentWillMount () {
if (Platform.OS === 'android') return
BackHandler.addEventListener('hardwareBackPress', () => {
const { dispatch, nav } = this.props
if (nav.routes.length === 1 && (nav.routes[0].routeName === 'Screen1')) {
return false
}
dispatch({ type: 'Navigation/BACK' })
return true
})
}
componentWillUnmount () {
if (Platform.OS === 'android') return
BackHandler.removeEventListener('hardwareBackPress')
}
render () {
return <navigatorApp navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav,
addListener: createReduxBoundAddListener('root')
})} />
}
}
const mapStateToProps = state => ({ nav: state.reducer })
export default connect(mapStateToProps)(HandleNavigation)
I also tried some given in other questions solutions, but nothing helped to prevent app closing.
I also thought about realizing backHandler on every screen.
In my app every screen contains function onPress for top button. That is why I tried to copy this action to hardware button using Backhandler. But all I get - screen goes back, and the app hides at the same time.
Is there any solution in my case to prevent closing app by pressing hw backbutton?
You can use BackHandler to exit/close the application:
import { BackHandler } from 'react-native';
BackHandler.exitApp();
Use react-navigation it has inbuilt backhandler.
After converting the app to redux, my react-navigation got some problem. Previously, before integrating with redux, when I press back button (Physical button) react-navigation back to the previous screen. After integrating with redux, the back button will close the app. But, it's still working with goBack() function.
I'm following the guide: https://reactnavigation.org/docs/guides/redux
And read some code from here : https://github.com/react-community/react-navigation/tree/master/examples/ReduxExample
And, this is my Navigator configuration
export const AppNavigator = StackNavigator(
{
Home: { screen: HomeScreen },
ChatDetail: { screen: ChatDetail },
PulsaDetail: { screen: PulsaDetailScreen },
Pulsa: { screen: Pulsa }
},
{
headerMode: 'none',
}
)
class AppWithNavigation extends Component {
render(){
return(
<AppNavigator navigation={ addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav,
})} />
)
}
}
const mapStateToProps = (state) => ({
nav: state.nav
})
export default connect(mapStateToProps)(AppWithNavigation)
EDIT: It's can be done with manual handle & dispatch back action, but it's can't do it automaticlly? just like before using redux?
BackHandler.addEventListener('hardwareBackPress',() => {
this.props.goBack()
return true
})
After post Github issue in react-navigation repository, I got the answer.
Should add manually the back listener on top of screen / component
// App.js
import { BackAndroid } from 'react-native'
// [...]
componentDidMount() {
BackAndroid.addEventListener('backPress', () => {
const { dispatch, nav } = this.props
if (shouldCloseApp(nav)) return false
dispatch({ type: 'Back' })
return true
})
}
componentWillUnmount() {
BackAndroid.removeEventListener('backPress')
}
// [...]
https://github.com/react-community/react-navigation/issues/2117
https://github.com/react-community/react-navigation/issues/117
UPDATE:
https://facebook.github.io/react-native/docs/backhandler
i am using React Native Share Method (https://facebook.github.io/react-native/docs/share.html) to share content on Android.
As per documentation, we can use it in following ways:
Share.share({
message: 'React Native | A framework for building native apps using React'
})
.then((result) => {
console.log(result.action) // returns sharedAction
})
.catch((error) => {
console.log(error)
})
So when we call Share method, we will get result in then and popup window is appeared which contains apps list with which we can share the message content.
Issue:
Popup window also contains a cancel button, so when user click on it, window get closed, but there is no method available/mentioned to capture it, in docs.
Is there any way to capture the cancel event, as i want to perform some action when user clicks on it.
Thanks in adv. :)
There is option in share dismissedAction but unfortunately this is IOS only . You can use react-native-share with prop "failOnCancel" to true and it will work on both android and ios
Sample Code
import React, { Component } from "react";
import { Button } from "react-native";
import Share from "react-native-share";
export default class ShareExample extends Component {
onShare = async () => {
const shareOptions = {
title: "Share file",
social: Share.Social.EMAIL,
failOnCancel: true
};
try {
const ShareResponse = await Share.open(shareOptions);
//setResult(JSON.stringify(ShareResponse, null, 2));
} catch (error) {
console.log("Error =>", error);
}
};
render() {
return <Button onPress={this.onShare} title="Share" />;
}
}
App Preview
This might help
import React, {Component} from 'react';
import {Share, Button} from 'react-native';
class ShareExample extends Component {
onShare = async () => {
try {
const result = await Share.share({
message:
'React Native | A framework for building native apps using React',
});
if (result.action === Share.sharedAction) {
if (result.activityType) {
// shared with activity type of result.activityType
} else {
// shared
}
} else if (result.action === Share.dismissedAction) {
// dismissed
}
} catch (error) {
alert(error.message);
}
};
render() {
return <Button onPress={this.onShare} title="Share" />;
}
}
I'm still doing my first steps in react native development for Android & iOS and I stumbled across a (supposedly simple) problem with buttons. I do not know how to modify a text field by pressing a button.
I tried using states, so this is how it currently looks like:
import React, { Component } from 'react';
import {
...
Button
} from 'react-native';
// more code
class ExampleButton extends ParseComponent {
constructor() {
super();
this.state = {
label: 'nothing'
}
}
// more code
render() {
if(...) {
return (
<Button
onPress={onButtonPress}
title="Click_test"
color="#841584"/>
);
}
}
const onButtonPress = () => { this.setState({label: 'something' });
However, I get an error message on pressing the button that says
... unexpected token, expected (....
in line const onButtonPress......
I'd be very about any hint! :) Thank you.
class ExampleButton extends ParseComponent {
constructor() {
super();
this.state = {
label: 'nothing'
}
}
// more code
onButtonPress = () => { //Make a property of ExampleButton class
this.setState({label: 'something' });
} //was missing this closing bracket
render() {
if(...) {
return (
<Button
onPress={this.onButtonPress} //change to this.onButtonPress
title="Click_test"
color="#841584"/>
);
}
}