ClearInterval Not working in React Native - javascript

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.

Related

setInterval keeps running even after clearInterval

Thanks in advance.
This is my question : It is Quiz website for couple.
Before partner finish quiz, It send get request to server every 5s.
but the problem is even partner's answers are set, setInterval never stops.
but if I refresh my website, It works well.
Can you please give me advise?
const postAnswers = useGetResults();
const postPartnerAnswers = useGetPartnerResults();
const [myResult, setMyResult] = useState<FinalAnswer | undefined>();
const [partnerResult, setPartnerResult] = useState<FinalAnswer | undefined>();
const [errorMessage, setErrorMessage] = useState<string | undefined>(undefined);
const [isLoading, setIsLoading] = useState<boolean>(false);
const init = async () => {
try {
const email = localStorage.getItem('email');
const partnerEmail = localStorage.getItem('partnerEmail');
if (email !== undefined && partnerEmail !== undefined) {
// localStorage에 이메일 값들이 있으면,
const result = await postAnswers(email, partnerEmail);
const otherResult = await postPartnerAnswers(email, partnerEmail);
if (result.answers !== undefined && otherResult.answers !== undefined) {
// 몽고디비에서 받아온 값이 둘다 있으면
setMyResult(result);
setPartnerResult(otherResult);
} else {
// 몽고디비에서 받아온 값이 없으면
console.log(result.answers, otherResult.answers);
setIsLoading(true);
}
}
} catch (error) {
setErrorMessage('로딩하는 도중 에러가 발생했습니다');
console.error(error);
}
};
useEffect(() => {
init();
}, []);
useEffect(() => {
if (myResult !== undefined && partnerResult !== undefined) {
setIsLoading(false);
console.log('둘다 값이 있어요!');
console.log(isLoading);
}
}, [myResult, partnerResult]);
const timer = () => {
return setInterval(() => {
init();
console.log('isLoading', isLoading);
if (isLoading === false) {
console.log('clear');
clearInterval(timer());
}
}, 5000);
};
useEffect(() => {
if (isLoading === true) {
console.log('둘다 값이 없어요!');
timer();
}
if (isLoading === false) {
console.log('clear');
clearInterval(timer());
}
}, [isLoading]);
deployed website : https://www.couple-quiz.com/
Expanding on #Ethansocal comment:
Your code is calling clearInterval(timer()) which will create a new interval that it will immediately clear. It seems that you are confusing the API of removeEventListener and clearInterval.
clearInterval should be called with the identifier returned by setInterval.
I suggest getting rid of the timer function and rewriting your last useEffect to make it return a cleanup function when isLoading is true:
useEffect(() => {
if (isLoading) {
console.log('둘다 값이 없어요!');
const interval = setInterval(init, 5_000);
return () => { clearInterval(interval) };
} else {
console.log('clear');
}
}, [isLoading]);

older call of function is overwriting the new one due to more execution time in react js

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]);

useLazyQuery onCompleted doesn't trigger

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)
}

Rendered fewer hooks than expected. This may be caused by an accidental early return statement

I'm getting this error when triggering a setState inside of a custom React hook. I'm not sure of how to fix it, can anyone show me what I'm doing wrong. It is getting the error when it hits handleSetReportState() line. How should I be setting the report state from inside the hook?
custom useinterval poll hook
export function usePoll(callback: IntervalFunction, delay: number) {
const savedCallback = useRef<IntervalFunction | null>()
useEffect(() => {
savedCallback.current = callback
}, [callback])
useEffect(() => {
function tick() {
if (savedCallback.current !== null) {
savedCallback.current()
}
}
const id = setInterval(tick, delay)
return () => clearInterval(id)
}, [delay])
}
React FC
const BankLink: React.FC = ({ report: _report }) => {
const [report, setReport] = React.useState(_report)
if ([...Statues].includes(report.status)) {
usePoll(async () => {
const initialStatus = _report.status
const { result } = await apiPost(`/links/search` });
const currentReport = result.results.filter((item: { id: string; }) => item.id === _report.id)
if (currentReport[0].status !== initialStatus) {
handleSetReportState(currentReport[0])
console.log('status changed')
} else {
console.log('status unchanged')
}
}, 5000)
}
... rest
This is because you put usePoll in if condition, see https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
You can put the condition into the callback
usePoll(async () => {
if ([...Statues].includes(report.status)) {
const initialStatus = _report.status
const { result } = await apiPost(`/links/search` });
const currentReport = result.results.filter((item: { id: string; }) => item.id === _report.id)
if (currentReport[0].status !== initialStatus) {
handleSetReportState(currentReport[0])
console.log('status changed')
} else {
console.log('status unchanged')
}
}
}, 5000)
And if the delay will affect report.status, use ref to store report.status and read from ref value in the callback.

How to stop setInterval() in React

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()
}

Categories