I use setInterval() to send GET request for state updating. I also use clearInterval() after the update process complete.
//
// getSynProcessState used for updating data by sending GET request to an API after every minute
//
intervalID = 0;
getSynProcessState = () => {
// get total and current sync
this.intervalID = setInterval(() => {
axios.get('http://mySite/data/')
.then(res => {
console.log(res.data)
});
},1000);
}
//
// clearInterval() will run if this.state.isSyncStart === false
//
componentDidUpdate() {
if (this.state.isSyncStart) {
this.getSynProcessState() //setInterval()
console.log('componentDidUpdate: ' + this.state.isSyncStart)
} else {
clearInterval(this.intervalID)
console.log('componentDidUpdate: ' + this.state.isSyncStart)
}
}
As you can see that when [this.state.isSyncStart === true] => setInterval() run OK
But when [this.state.isSyncStart === false] => clearInterval() run but the GET requests keep sending
You are overwriting the current interval in your componentDidUpdate call. Do a check e.g.
if (this.state.isSyncStart) {
this.interValID == 0 && this.getSynProcessState() //setInterval()
console.log('componentDidUpdate: ' + this.state.isSyncStart)
} else {
clearInterval(this.intervalID)
console.log('componentDidUpdate: ' + this.state.isSyncStart)
}
I somehow solved the problem by adding runOnce and set it in the 'If' Condition. Maybe it prevent the overwriting on [this.intervalID]
runOnce = true
getSynProcessState = () => {
if (this.state.isSyncStart && this.runOnce) {
this.runOnce = false
this.intervalID = setInterval(() => {
axios.get('http://192.168.51.28:8031/process/')
.then(res => {
console.log(res.data)
// this.setState({
// total: res.data.total,
// current: res.data.current
// })
// console.log('1: ' +this.state.total)
});
},200);
} else {
clearInterval(this.intervalID)
}
}
componentDidUpdate() {
this.getSynProcessState()
}
Related
I created a function that fetches cart items from the API
There are 2 API one is for authenticated users and the other is for non-authenticated users
But the execution of the non-authenticated users takes more time to get data that's why it even overwrites the data for the authenticated user
So how can I solve this problem
Inside the context
usestate to call the cart function
useEffect(() => {
console.log("the value of user", userAuthenticated);
if (userAuthenticated == true) {
cartdataupdater("useEffect");
} else {
cartdataupdater("useEffect withou");
}
}, [userAuthenticated]);
cart updater
const cartdataupdater = (from = "this") => {
console.log(" worken", userAuthenticated, from);
var startTime = performance.now();
if (userAuthenticated == true) {
axios.get(`http://127.0.0.1:8000/core/cart/1/`).then((response) => {
setcartData(response.data);
console.log("the end is not good");
var endTime = performance.now();
console.log(
`Call to doSomething took ${
endTime - startTime
} milliseconds`
);
});
} else {
console.log("not authenticated");
var startTime = performance.now();
axios
.get(
`http://127.0.0.1:8000/core/dcart/${localStorage.getItem(
"cart_id"
)}`
)
.then((response) => {
setcartData(response.data);
console.log("the end");
console.log(from);
var endTime = performance.now();
console.log(
`Call to doSomething took ${
endTime - startTime
} milliseconds`
);
});
}
};
Thanks in advance
I anything is required I will provide you
I founded the soltion
I solve it by adding the loading state which helps me to stop the extra request
const cartdataupdater = () => {
if (userAuthenticated == true) {
axios.get(`http://127.0.0.1:8000/core/cart/1/`).then((response) => {
setcartData(response.data);
});
} else {
try {
axios
.get(
`http://127.0.0.1:8000/core/dcart/${localStorage.getItem(
"cart_id"
)}`
)
.then((response) => {
setcartData(response.data);
});
} catch (error) {
console.log(error);
}
}
};
useEffect(() => {
if (userauthloading == false) {
cartdataupdater();
}
}, [userauthloading, userAuthenticated]);
I am running the query every 1 minute to check the progress.
let timer = null
const [inProgress, setInProgress] = useState(false)
const [
checkProgress,
{ loading2, data2 }
] = useLazyQuery(CHECK_PROGRESS, {
fetchPolicy: 'cache-and-network',
onCompleted: (data) => {
if(data.progress.completed) {
setInProgress(false)
// some code
} else {
// some code
}
}
}
)
useEffect(() => {
if (inProgress) {
timer = setInterval(() => {
checkProgress()
}, 1000 * 60)
} else {
clearInterval(timer)
}
return () => {
clearInterval(timer)
}
}, [inProgress])
onCompleted doesn't trigger once data.progress.completed is changed from false to true.
But the query is still running every 1 minute.
Any idea to fix this?
The issue was on the backend. I was setting null for non-null field.
I found the error after adding onError callback.
onError: (error) => {
console.log(error)
}
I have the below code in a vue application
mounted: function () {
this.timer = setInterval(async () => {
if (this.progress >= 1) {
this.progress = 1
clearInterval(this.timer)
}
console.log('update')
const id = this.$route.params.id
const progOut = await this.api.get(`/api/mu/job/${id}/status`)
const response = progOut.data
this.progress = response.data.progress / 100
this.state = response.data.status
}, 7000)
},
I was expecting it to execute the get request every 7 seconds but it is executing the call every 500ms approx
I read other answers and so far I think this is the proper way but the code is executing too many requests
What is the proper way to call a function from within the setInterval to make it actually wait the timeout?
Edit: This was my final code in case someone goes through the same
methods: {
redirect (page) {
if (page === 'FINISHED') {
this.$router.push({
name: 'viewReport',
params: { id: 4 }
})
} else {
this.$router.push({
name: 'errorOnReport',
params: { id: 13 }
})
}
}
},
watch: {
state: async function (newVal, old) {
console.log('old ' + old + ' newVal ' + newVal)
if (newVal === 'FAILED' || newVal === 'FINISHED') {
this.redirect(newVal)
}
}
},
data () {
return {
state: null,
timer: null,
progress: 0.0,
progressStr: '0%'
}
},
mounted () {
const update = async () => {
if (this.progress >= 1) {
this.progress = 1
}
console.log('update ' + new Date())
const id = this.$route.params.id
const progOut = await this.api.get(`/api/mu/job/${id}/status`)
const response = progOut.data
this.state = response.data.status
this.progress = response.data.progress / 100
this.progressStr = response.data.progress + '%'
}
update()
this.timer = setInterval(update, 10000)
},
beforeUnmount () {
clearInterval(this.timer)
}
A better design is to wrap setTimeout with a promise, and do the polling in an async method that loops...
mounted: function() {
this.continuePolling = true; // suggestion: we have to stop sometime. consider adding continuePolling to data
this.poll();
},
unmounted: function() { // almost the latest possible stop
this.continuePolling = false;
},
methods:
async poll(interval) {
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
while(this.continuePolling) {
await this.updateProgress();
await delay(7000);
}
},
async updateProgress() {
const id = this.$route.params.id
const progOut = await this.api.get(`/api/mu/job/${id}/status`)
const result = progOut.data.data;
this.progress = result.progress / 100
this.state = result.status
}
i'm try to clear interval when the user in not in the detail section and if match the status is 1, my code like this :
useEffect(() => {
console.log(section)
console.log('ini interval lo', interval)
if (section !== "detailCheckIn") {
clearInterval(interval);
console.log('aa', clearInterval(interval) ? true : false)
}
console.log('section di : ', section)
}, [section]);
const checkStatus = (data) => {
console.log('datanya nih ', data)
interval = setInterval(() => {
console.log('ini test interval', userToken)
consume.getWithParams('CheckinInfo', {}, { token }, { checkin_id: data })
.then(response => {
console.log('ini tuh response', response)
//ubah jadi 1 kalomau final test
if (response.result.status === 1) {
navigation.navigate('Service')
clearInterval(interval);
console.log('di clear')
AsyncStorage.setItem('isCheckIn', 'udah check in nih')
}
})
.catch(err => {
console.log(err)
console.log('token error', token)
})
}, 2000);
}
when i'm console log the clear interval, that return false
Try this. Notice the use of useRef to store a single reference to _interval, and how this is only ever changed through the functions clearCurrentInterval and replaceCurrentInterval.
If you only update your interval through these two functions, you can be sure you will only ever have one interval at a time, as your previous interval always gets cleared first.
const _interval = useRef(null);
const interval = () => _interval.current;
const clearCurrentInterval = () => {
clearInterval(interval());
};
const replaceCurrentInterval = (newInterval) => {
clearCurrentInterval();
_interval.current = newInterval;
};
useEffect(() => {
console.log(section);
console.log("ini interval lo", interval());
if (section !== "detailCheckIn") {
clearCurrentInterval();
}
console.log("section di : ", section);
}, [section]);
const checkStatus = (data) => {
console.log("datanya nih ", data);
const newInterval = setInterval(() => {
console.log("ini test interval", userToken);
consume
.getWithParams("CheckinInfo", {}, { token }, { checkin_id: data })
.then((response) => {
console.log("ini tuh response", response);
//ubah jadi 1 kalomau final test
if (response.result.status === 1) {
navigation.navigate("Service");
clearCurrentInterval();
console.log("di clear");
AsyncStorage.setItem("isCheckIn", "udah check in nih");
}
})
.catch((err) => {
console.log(err);
console.log("token error", token);
});
}, 2000);
replaceCurrentInterval(newInterval);
};
However, depending on how you're using this, you might be better off just having a useEffect that creates a single interval when the component mounts, and clears it when it unmounts or gets the API response you want.
EDITED: I want to store a timestamp when the react native app goes into the background, to see if re-login is needed. I use the async storage to save the timestamp on the device, with help of the appstate functionality.
But the getItem and setItem code never executes. any idea why ?
componentDidMount() {
AppState.addEventListener('change', this._handleAppStateChange);
}
_handleAppStateChange = (nextAppState: any) => {
if (
this.state.appState.match(/inactive|background/) &&
nextAppState === 'active'
) {
this.getTime();
this.checkTimeStamp();
console.log(this.state.time, 'time var');
console.log('app is active, and has been in the background');
} else if (
this.state.appState == 'active' &&
nextAppState == 'active'
) {
this.setTime();
this.checkTimeStamp();
console.log(this.state.time, 'time var');
console.log('app is active, and just opened.');
} else {
this.setTime()
//sets the timestamp
console.log('app in background or closed');
}
this.setState({ appState: nextAppState });
};
async setTime() {
let seconds = this.generateTime();
try {
const val = await AsyncStorage.setItem('time', seconds.toString());
this.setState({ time: Number(val) });
} catch (error) {
console.error('onRejected function called: ' + error);
}
}
async getTime() {
let please = await AsyncStorage.getItem('time');
this.setState({ time: Number(please) });
console.log(this.state.time, 'time var');
}
Take a look at AppState https://facebook.github.io/react-native/docs/appstate
It allows you to listen for "active"/"background" state changes.