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.
Related
I want to test like this.
Case 1: Error
Cannot spy the inner property because it is not a function; undefined given instead.
Component.vue
export default {
setup() {
function outer() {
inner();
}
function inner() {
// do something for only outer function
}
return { outer };
}
};
Component.spec.js
it('what can I do?', () => {
wrapper.vm.inner = jest.fn(); // throw error
wrapper.vm.outer();
expect(wrapper.vm.inner).toBeCalled();
});
Case 2: Error
Component.vue
export default {
setup() {
function outer() {
inner();
}
function inner() {
// ...
}
return { outer, inner }; // add inner
}
};
Component.spec.js
it('what can I do?', () => {
wrapper.vm.inner = jest.fn();
wrapper.vm.outer();
expect(wrapper.vm.inner).toBeCalled();
});
expect(jest.fn()).toBeCalled()
Expected number of calls: >= 1
Received number of calls: 0
Case 3: Pass
it('what can I do?', () => {
wrapper.vm.outer = jest.fn(() => wrapper.vm.inner());
jest.spyOn(wrapper.vm, 'inner');
wrapper.vm.outer();
expect(wrapper.vm.inner).toBeCalled();
});
This case is not pretty...
Can't I get "inner()" without including it in "return"?
These methods pass when implemented in options api. But I want to use only setup().
Self Answer
I found a way. I made a class like this.
Util.js
class Util {
outer() {
this.inner();
}
inner() {
// do something...
}
}
Component.vue
setup() {
const util = reactive(new Util());
function call() {
util.outer();
}
return { util, call };
}
Component.spec.js
it('is this way correct?', () => {
jest.spyOn(wrapper.vm.util, 'outer');
jest.spyOn(wrapper.vm.util, 'inner');
await wrapper.vm.call();
expect(wrapper.vm.util.outer).toBeCalledTimes(1);
expect(wrapper.vm.util.inner).toBeCalledTimes(1);
});
i have similar architecture in my app.
computed(){
someStoreValue = this.$store.someStoreValue;
}
watch() {
someStoreValue() = async function () {
//do some async action
}
},
methods: {
someAction() {
this.$store.someStoreValue = 'NEW VALUE'
//await for "watch"
//do stuff
}
}
I need to "someAction" await for "someStoreValue" watcher ends.
I need this kind of architecture someStoreValue can be changed in many places.
Sure, you can't make your watchers async, which is pretty senseless since the data you are after has already arrived.
someStoreValue(newValue, oldValue) {
// But you can still call other async functions.
// Async functions are just functions that returns a promise. Thus:
doSomeAsyncAction().then(this.someAction)
}
Still, why not just do your async stuff in someAction instead?
watch:{
someStoreValue(newValue, oldValue) {
this.someAction()
}
},
methods:{
async someAction(){
await doSomeAsyncStuff() // What prevents you from doing this?
//do stuff
}
}
You can use a flag and wait for it.
data() {
return {
flag: false
}
},
watch() {
someStoreValue() = async function () {
//do some async action
flag = true;
}
},
methods: {
async someAction() {
this.$store.someStoreValue = 'NEW VALUE'
await new Promise((resolve) => {
if (this.flag) {
resolve();
} else {
const unwatch = this.$watch('flag', (newVal) => {
if (newVal) {
unwatch();
resolve();
}
});
}
});
//do stuff
}
}
Maybe in this case the #ippi solution is better, but you can use this approach in other cases.
I have this useFocusEffect function:
useFocusEffect(
useCallback(() => {
async function setFilterValue() {
let filterValue = await AsyncStorage.getItem('filterValue');
let inputValue = JSON.parse(filterValue);
if (gpsFilterValue === null) {
setGpsFilterValue(inputValue);
console.log('null')
// setRefreshing(true)
} else if (inputValue !== parseInt(gpsFilterValue)) {
setGpsFilterValue(inputValue);
console.log('refreshing1')
setTimeout(() => {
console.log(gpsFilterValue)
}, 1000);
//console.log(inputValue + ' ' + gpsFilterValue)
//setRefreshing(true)
} else {
console.log('test')
}
}
setFilterValue();
}, [])
);
When I debug the gpsFilterValue in the setTimeout it stays undefined, but when I make a button in the render to debug the gpsFilterValue state value and press it, it has updated. How come the values are different?
From the looks of it gpsFilterValue is part of your state as you have a state setter being invoked in the callback. However, your useCallback isn't listing gpsFilterValue as a dependency (that empty array that is the second parameter to useCallback. Add it to that dependency list and you should see the updated value.
useFocusEffect(
useCallback(() => {
async function setFilterValue() {
let filterValue = await AsyncStorage.getItem('filterValue');
let inputValue = JSON.parse(filterValue);
if (gpsFilterValue === null) {
setGpsFilterValue(inputValue);
console.log('null')
// setRefreshing(true)
} else if (inputValue !== parseInt(gpsFilterValue)) {
setGpsFilterValue(inputValue);
console.log('refreshing1')
setTimeout(() => {
console.log(gpsFilterValue)
}, 1000);
//console.log(inputValue + ' ' + gpsFilterValue)
//setRefreshing(true)
} else {
console.log('test')
}
}
setFilterValue();
}, [gpsFilterValue])
);
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
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);
}
}