I am setting up a setInterval with some VideoPlayer iFrame. Every 10 seconds or so, I need to call an API to update back-end with new state of the video played.
I want to have another check on client, if the data from previous state is same as new one (This case occurs when the video is paused for longer duration) I don't want to call the back-end API.
const [coveredArray, setCoveredArray] = useState([]);
const intervalPeriod = 5000;
const interval = useRef();
useEffect(() => {
if (typeof window !== "undefined" && isOpen && player) {
console.log('SUB');
// Setup an interval to update watch time
interval.current = window.setInterval(async () => {
const totalCoveredArray = await player?.api.getTotalCoveredArray();
setCoveredArray((prevCoveredArray) => {
console.log('1', prevCoveredArray);
console.log('2', totalCoveredArray);
if (!isEqual(prevCoveredArray, totalCoveredArray)) {
console.log('New');
return totalCoveredArray;
} else {
console.log('Same');
return prevCoveredArray;
}
});
}, intervalPeriod);
return () => {
// Clear interval on exit
console.log('UN-SUB')
setCoveredArray([]);
return window.clearInterval(interval.current)
};
}
}, [isOpen, player]);
The problem with this code is, prevCoveredArray and totalCoveredArray are same everytime the interval is run. How is previousState similar to newState (which is not set yet)?
This is logged in console:
Any help/pointer would be helpful, thanks.
Related
I'm currently trying to create a stopwatch component using React Native and the setInterval function to increment a counter and set the new value to state like so:
Play Function(this runs after hitting the play button)
const [isRunning, setisRunning] = useRecoilState(runState);
const [time, setTime] = useRecoilState(timeState);
const [timerRef, setTimerRef] = useState(0);
const Play = useCallback(() => {
window.clearInterval(interval); //clear the interval
if (isRunning === false) { //set the isRunning state to true
setisRunning((isRunning) => !isRunning);
interval = window.setInterval(() => { //setInterval operation
setTime((previousTime) => previousTime + 1);
}, 100);
setTimerRef(interval); //setTimer reference to pause
}
}, [time]);
Pause Function(this runs after hitting the pause button)
const Pause = () => {
if (isRunning === true) {
setisRunning((isRunning) => !isRunning);
window.clearInterval(timerRef);
}
};
My problem is that the timer tends to speed up erratically an as such I'm not able to use the time value passed. I'm not sure where I am going wrong, kindly assist.
Ok so Iv've run into this quite recently in my next.js project. The correct way to do it seems like something like that:
useEffect(() => {
const interval = setInterval(() => {
console.log('This will run every second!');
}, 1000);
return () => clearInterval(interval);
}, []);
See for example here
how can i call two permanent services, i want to call the first service every 5 seconds, after once results of the first service return a value different from 0, I want to call a second service with the value returned by the first service every 5 seconds also, until I receive a value, How can I do this with react setInterval doesn't work.
const {info,data} = useSelector((state) => ({
info : state.reducerData.info,
data : state.reducerData.data,
})
useEffect(() =>{
var refreshIntervalId = setInterval(() => {
dispatch(getData(id));
},(5000))
if(data?.sum != 0){
clearInterval(refreshIntervalId)
}
},[id])
useEffect(() =>{
var interval = setInterval(() => {
if(data?.sum !=0){
dispatch(getInfoData())
}
},(5000))
if( info == sum){
clearInterval(interval)
}
},[data])
i'm working on a continuous notification (every 3 seconds and max 1 min), until user accept pending orders.
This is my code.
usePrevious is custom hook that gives me previous value of state.
I don't mind why, when setTimeout executes clearInterval(), 'notification' is null.
This problem cause loop in sound.
[.....]
const [notification, setNotification] = useState(null)
const previousOrderCount = usePrevious(newOrderCount)
const previousPendingReservationsLength = usePrevious(
pendingReservationsLength
)
const isToneActive = useRef(false)
// sound notify for new orders
useEffect(() => {
if (
!isToneActive.current &&
newOrderCount > previousOrderCount &&
user?.profile?.role === "manager"
) {
// this prevent multiple triggers of sound
isToneActive.current = true
setNotification(setInterval(() => playNotification(), 3000))
setTimeout(() => {
clearInterval(notification)
isToneActive.current = false
}, 60000)
}
}, [
newOrderCount,
playNotification,
user,
previousOrderCount,
stopNotify,
notification,
setNotification,
])
[....]
I would use another React ref to hold a reference to the interval timer. The issue here is that React state updates are asynchronous, so the setNotification state update doesn't immediately update the notification state for the setTimeout callback that encloses the current null state value.
const notificationRef = React.useRef(null);
...
notificationRef.current = setInterval(() => playNotification(), 3000);
setTimeout(() => {
clearInterval(notificationRef.current);
notificationRef.current = null;
isToneActive.current = false;
}, 60000);
So I am writing a product prototype in create-react-app, and in my App.js, inside the app() function, I have:
const [showCanvas, setShowCanvas] = useState(true)
This state is controlled by a button with an onClick function; And then I have a function, inside it, the detectDots function should be ran in an interval:
const runFaceDots = async (key, dot) => {
const net = await facemesh.load(...);
setInterval(() => {
detectDots(net, key, dot);
}, 10);
// return ()=>clearInterval(interval);};
And the detectDots function works like this:
const detectDots = async (net, key, dot) => {
...
console.log(showCanvas);
requestFrame(()=>{drawDots(..., showCanvas)});
}
}};
I have a useEffect like this:
useEffect(()=>{
runFaceDots(); return () => {clearInterval(runFaceDots)}}, [showCanvas])
And finally, I can change the state by clicking these two buttons:
return (
...
<Button
onClick={()=>{setShowCanvas(true)}}>
Show Canvas
</Button>
<Button
onClick={()=> {setShowCanvas(false)}}>
Hide Canvas
</Button>
...
</div>);
I checked a few posts online, saying that not clearing interval would cause state loss. In my case, I see some strange behaviour from useEffect: when I use onClick to setShowCanvas(false), the console shows that console.log(showCanvas) keeps switching from true to false back and forth.
a screenshot of the console message
you can see initially, the showCanvas state was true, which makes sense. But when I clicked the "hide canvas" button, and I only clicked it once, the showCanvas was set to false, and it should stay false, because I did not click the "show canvas" button.
I am very confused and hope someone could help.
Try using useCallback for runFaceDots function - https://reactjs.org/docs/hooks-reference.html#usecallback
And ensure you return the setInterval variable to clear the timer.
const runFaceDots = useCallback(async (key, dot) => {
const net = await facemesh.load(...);
const timer = setInterval(() => {
detectDots(net, key, dot);
}, 10);
return timer //this is to be used for clearing the interval
},[showCanvas])
Then change useEffect to this - running the function only if showCanvas is true
useEffect(()=>{
if (showCanvas) {
const timer = runFaceDots();
return () => {clearInterval(timer)}
}
}, [showCanvas])
Update: Using a global timer
let timer // <-- create the variable outside the component.
const MyComponent = () => {
.....
useEffect(()=>{
if (showCanvas) {
runFaceDots(); // You can remove const timer here
return () => {clearInterval(timer)}
} else {
clearInterval(timer) //<-- clear the interval when hiding
}
}, [showCanvas])
const runFaceDots = useCallback(async (key, dot) => {
const net = await facemesh.load(...);
timer = setInterval(() => { //<--- remove const and use global variable
detectDots(net, key, dot);
}, 10);
return timer //this is to be used for clearing the interval
},[showCanvas])
.....
}
I ultimately want to display a modal to the user if a certain condition is met after X seconds of the app execution.
However, I keep getting a warning about setting a timer for a long period of time (a few minutes) on android, but my timer only has a few seconds.
const surveyCheckTime = 3000; // X = 3 seconds
const App = () => {
// First Time Modal State
const [surveyVisibility, setSurveyVisibility] = useState(false);
const handleSurveyOpen = () => {
setSurveyVisibility(true);
};
const handleSurveyClose = () => {
setSurveyVisibility(false);
};
useEffect(() => {
const timer = setTimeout(() => {
console.log('0:FROM_APP: Checking for condition: ');
getData().then(
keyValue => {
console.log('0:FROM_APP: Completion status: ', keyValue);
if (keyValue === 'false' || keyValue === undefined) {
handleSurveyOpen();
}
},
error => {
// console.log('Survery_Error: ', error);
},
);
}, surveyCheckTime);
return () => clearTimeout(timer);
}, []);
return (
<View>
...
<SurveyModal
surveyVisibility={surveyVisibility}
handleSurveyClose={handleSurveyClose}
/>
</View>
)
getData() is an async function returning keyValue as promise.
export const getData = async (myKey = 'alreadyOpened') => {
try {
const value = await AsyncStorage.getItem(`#${myKey}`);
if (value !== null) {
// value previously stored
// console.log('FROM__getData: Stored previously: ', value);
return value;
}
} catch (e) {
// error reading value
console.log('ERROR:FROM__getData: Cannot read: ', e);
return 'fasle';
}
};
All is good and everything works as intended but I keep getting this warning with a different last line everytime:
(Saw setTimeout with duration Y ms) Y is way higher than my X value
There is this question but it's not exactly firebase related in my case. (Although I do use firebase to fetch data inside another component but it shouldn't be the issue) IT IS THE ISSUE
I've looked into this, but most of the solutions either change the "node_modules" or disable the warning and the topic is pretty much outdated.
It would be best If there's a more efficient solution of handling timeouts.
EDIT: "firebase": "7.13.1" is what's causing the issue when fetching data
I was using a deprecated integration of firebase which was causing this issue, (web config and not .json file)