can't remove android backHandler - react-native

I find this code to handle the back button on android :
componentDidMount() {
this.handleAndroidBackButton ();
}
componentWillUnmount () {
this.removeAndroidBackButtonHandler();
}
handleAndroidBackButton = () => {
BackHandler.addEventListener('hardwareBackPress', () => {
this.showModal1(true);
return true;
});
};
removeAndroidBackButtonHandler = () => {
BackHandler.removeEventListener('hardwareBackPress', () => {});
}
it works fine but when I go to the other page, I still have the same behaviour.
I find this on stackoverflow:
constructor() {
this._onBackButton= this._onBackButton.bind(this)
}
_onBackButton() {
return true;
}
and I changed my code to this:
constructor(props){
super(props)
this.state = {
transData: [],
...
}
this._onBackButton = this._onBackButton.bind(this);
}
_onBackButton = () => {
return true;
};
componentDidMount() {
this.handleAndroidBackButton();
...
}
componentWillUnmount () {
this.removeAndroidBackButtonHandler();
}
handleAndroidBackButton = () => {
BackHandler.addEventListener('hardwareBackPress', this._onBackButton);
};
removeAndroidBackButtonHandler = () => {
BackHandler.removeEventListener('hardwareBackPress', this._onBackButton);
}
I don't have any error now but it doesn't work ! it doesn't remove event listener in other screens

The AndroidBakHandler you're having is named _onBackButton ... but you're binding a method called _onBack ... So just rename your backHandler to be _onBackButton and make it arrow-function (Auto bound to your class ... that's why you wouldn't need to bind it in the constructor)
// constructor() {
// No need for the next line ... arrow function is bound automatically
// this._onBackButton = this._onBackButton.bind(this);
// }
_onBackButton = () => {
return true;
};
-
removeAndroidBackButtonHandler = () => {
BackHandler.removeEventListener('hardwareBackPress',
() => {}); // <- look at that
}
Regarding: "It works fine but when I go to the other page, I still have the same behaviour."
It's because when you navigate into another screen (Your component is not unmounted) ... and you're removing your android-back-handler in componentWillUnmount ...
So I'd suggest you remove your event-listener when you navigate to another screen not in componentWillUnmount
Also make sure you have you add your android-back-handler when your screen receives focus again

Related

removeEventListener is Deprecated and i don't achieve to refacto it properly

Linking.removeEventListener('url', onReceiveURL);
removeEventListener is deprecated.
This is what my IDE suggests :
EventEmitter.removeListener('url', ...): Method has been deprecated.
Please instead use remove() on the subscription returned by
EventEmitter.addListener.
// Custom function to subscribe to incoming links
subscribe(listener: (deeplink: string) => void) {
// First, you may want to do the default deep link handling
const onReceiveURL = ({url}: {url: string}) => listener(url);
// Listen to incoming links from deep linking
Linking.addEventListener('url', onReceiveURL);
const handleDynamicLink = (
dynamicLink: FirebaseDynamicLinksTypes.DynamicLink,
) => {
listener(dynamicLink.url);
};
const unsubscribeToDynamicLinks = dynamicLinks().onLink(handleDynamicLink);
return () => {
unsubscribeToDynamicLinks();
Linking.removeEventListener('url', onReceiveURL);
};
I tried many things but nothing seems to work.
Didn't find any concrete information about it.
Any help to figure it out ?
EDIT -> I will investigate further but so far it's working :
const unsubscribeToDynamicLinks : any = ...
then in return :
return () => {
unsubscribeToDynamicLinks().remove('url', onReceiveURL);};
For the new API, this is how it works:
useEffect (() => {
const subscription = Linking.addEventListener('url', onReceiveURL);
return () => subscription.remove();
}, [])
For class components you can use something like below:
class MyClass extends Component {
constructor(props){
super(props)
this.changeEventListener = null
}
componentDidMount(){
// or you can use constructor for this
this.changeEventListener = AppState.addEventListener('change', () => {
// your listener function
})
}
componentWillUnmount() {
this.changeEventListener.remove()
}
}

Updating a state variable in React Native Expo

I dont really understand how setState and state variables update and work in React Native. Im trying to figure out what I did wrong in the code below, because I'm updating my tokenArray variable, but when I console log it in another function it is empty. Please help.
constructor() {
super()
this.state = {
tokenArr: []
}
}
componentDidMount() {
this.grabToken()
}
firebaseInformation = async () => {
var tokens = []
firebase.database().ref(`tokens/`).once('value', snapshot => {
const token = Object.values(snapshot.val());
token.map((item) => {
tokens.push(item.data)
})
return this.setState({
tokenArr: tokens
})
})
}
grabToken = async () => {
this.firebaseInformation()
console.log(this.state.tokenArr)
}
The fix was just to call the grabToken function in my render method instead (I was only calling it from my componentDidMount and didn't understand why it wasn't updating my state variable properly.
Return the array and set the state in componentDidMount() like this
componentDidMount() {
this.firebaseInformation()
.then((arr) => this.setState({ tokenArr: arr }))
.then(this.state.tokenArr);
}
firebaseInformation = async () => {
var tokens = []
firebase.database().ref(`tokens/`).once('value', snapshot => {
const token = Object.values(snapshot.val());
token.map((item) => {
tokens.push(item.data)
})
return tokenArr;
})
}

Handle back press on react native depending on component state

I'm trying to customize the back navigation event on my react native app. Basically, in the body of the component I render different sections depending on the currentSection state variable. What I found out is that the value of currentSection inside the onBackPress function does not get updated, and apparently always has the value of when it was first called (during the useEffect invocation).
const [currentSection, setCurrentSection] = useState<ProviderDetailSections>(ProviderDetailSections.MAIN);
useEffect(() => {
BackHandler.addEventListener(
"hardwareBackPress",
onBackPress
);
return () => BackHandler.removeEventListener(
"hardwareBackPress",
onBackPress
);
}, []);
function onBackPress(): boolean {
console.log(`onBackPress currentSection: ${currentSection}`);
if (currentSection === ProviderDetailSections.MAIN) {
return false;
}
else {
setCurrentSection(ProviderDetailSections.MAIN);
return true;
}
}
The console.log() inside onBackPress always logs the same section (MAIN), no matter what is the actual current section.
Any help would be greatly appreciated!
Check the answer
const [currentSection, setCurrentSection] = useState<ProviderDetailSections>(ProviderDetailSections.MAIN);
useEffect(() => {
BackHandler.addEventListener(
"hardwareBackPress",
onBackPress
);
return () => BackHandler.removeEventListener(
"hardwareBackPress",
onBackPress
);
}, []);
function onBackPress(): boolean {
console.log(`onBackPress currentSection: ${currentSection}`);
setCurrentSection(ProviderDetailSections.MAIN);
return true;
}
}
I've just encountered the same problem - the root of it is the fact, that your useEffect() function is called only once when the component is rendered, and I think the eventListeners are then created for the component with default values, which means your currentSection has default value for your BackHandler functions at all times. What you have to do is add currentSection to dependency array in your useEffect().
const [currentSection, setCurrentSection] = useState<ProviderDetailSections>(ProviderDetailSections.MAIN);
useEffect(() => {
BackHandler.addEventListener(
"hardwareBackPress",
onBackPress
);
return () => BackHandler.removeEventListener(
"hardwareBackPress",
onBackPress
);
}, [currentSection]);
function onBackPress(): boolean {
console.log(`onBackPress currentSection: ${currentSection}`);
if (currentSection === ProviderDetailSections.MAIN) {
return false;
}
else {
setCurrentSection(ProviderDetailSections.MAIN);
return true;
}
}

this.backPressed is not a function

I implemented it in sample , it works but in my main project it's displaying error message that backPressed is not a function.
backPressed = () => {
setTimeout(function() {
//Put All Your Code Here, Which You Want To Execute After Some Delay Time.
BackHandler.exitApp();
}, 3000);
};
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.backPressed);
}
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.backPressed);
}
static getDerivedStateFromProps(nextProps, prevState) {
const { userdata } = nextProps.UserDetailReducer;
const { UpdatingFailure } = nextProps.UpdateUserImageReducer;
if (UpdatingFailure) {
return {
avatarSource: ""
};
}
if (userdata.kenkoScore != "" && userdata.kenkoScore > 0) {
setTimeout(() => {
AsyncStorage.setItem("SCORE_FETCHED", "Yes");
nextProps.navigation.navigate("TabNavigation");
}, 100);
return null;
} else {
***this.backPressed();***
}
if (userdata) {
return { userDetail: userdata };
}
return null;
}
In componentDidMount it is working but in getDerivedStateFromProps not working
getDerivedStateFromProps is static so this refers to the class itself, not an instance of the class.
Make backPressed static to call it from getDerivedStateFromProps. You'll also need to update componentWillUnmount and componentDidMount to ComponentName.backPressed or this.constructor.backPressed. Note that making backPressed static means you won't be able to access this for props or state in the future.

Angular5- setInterval whiten the page

I am adding notification to my project. The website should shown a number of notification numbers that the user have got without refreshing page. To do so i have used setInterval function inside ngOnInit but when i used it inside ngOnInit the page goes white and shows nothing but the timer is still running.
Here is how i have implement the code.
ngOnInit
ngOnInit() {
this.subscription = this.loginInfoService.getLoginChangeEmitter()
.subscribe(item => this.loginSuccess(item));
this.subscription = this.loginInfoService.getSiteNameEmitter()
.subscribe(item => this.getSiteName(item));
this.subscription = this.loginInfoService.getSiteDescriptionEmitter()
.subscribe(item => this.getSiteDescription(item));
if (innerWidth < 766) {
this.notificationBell = true;
} else {
this.notificationBell = false;
}
//if i add this line page goes white
setInterval(() => {
this.getAllNotification();
}, 3000);
}
Code to get all notification
getAllNotification() {
this.unSeenNotification = [];
this.notificationService.getAllNotifications().subscribe(
result => {
this.notificationModel = result;
this.showLoading = false;
result.forEach(result => {
if (!result.isSeen) {
this.unSeenNotification.push(result);
}
})
this.notificationCount = this.unSeenNotification.length;
},
error => {
this.alertService.error(error, "Error!");
});
}
You can below window interval:
export class FoobarComponent implements OnInit {
static intervalId: Number;
ngOnInit(): void {
this.startInterval();
}
startInterval() void {
if(FoobarComponent.intervalId) { // always undefined
window.clearInterval(this.intervalId);
}
FoobarComponent.intervalId = window.setInterval(() => {
console.log('Hi'); }, 1000);
}
}