Update parameters of constructor functions on-the-go in React js - javascript

What's up guys! Here's the thing. I want to build metronome. I've tried to do so with setInterval or setTimeout, but those methods are unaccurate at all. So I've found this beautiful constructor function, which can make every tick of metronome pretty accurate.
function Timer(callback, timeInterval, options) {
this.timeInterval = timeInterval;
// Add method to start timer
this.start = () => {
// Set the expected time. The moment in time we start the timer plus whatever the time interval is.
this.expected = Date.now() + this.timeInterval;
// Start the timeout and save the id in a property, so we can cancel it later
this.theTimeout = null;
if (options.immediate) {
callback();
}
this.timeout = setTimeout(this.round, this.timeInterval);
console.log('Timer Started');
}
// Add method to stop timer
this.stop = () => {
clearTimeout(this.timeout);
console.log('Timer Stopped');
}
// Round method that takes care of running the callback and adjusting the time
this.round = () => {
console.log('timeout', this.timeout);
// The drift will be the current moment in time for this round minus the expected time..
let drift = Date.now() - this.expected;
// Run error callback if drift is greater than time interval, and if the callback is provided
if (drift > this.timeInterval) {
// If error callback is provided
if (options.errorCallback) {
options.errorCallback();
}
}
callback();
// Increment expected time by time interval for every round after running the callback function.
this.expected += this.timeInterval;
console.log('Drift:', drift);
console.log('Next round time interval:', this.timeInterval - drift);
// Run timeout again and set the timeInterval of the next iteration to the original time interval minus the drift.
this.timeout = setTimeout(this.round, this.timeInterval - drift);
}
}
export default Timer;
Here's what I do in my App.js (parts of the code we need):
import pop from "../audio/pop.mp3";
import Timer from "../constants/timer";
const [play, setPlay] = useState(false);
const [bpm, setBpm] = useState(40);
const [rate, setRate] = useState();
const popSound = new Audio(pop);
const playPop = () => {
popSound.play();
};
const metronome = new Timer(playPop, rate, { immediate: true });
const handlePlay = () => {
if (play) {
metronome.stop();
} else {
metronome.start();
}
};
useEffect(() => {
setRate((60 / bpm) * 1000);
console.log(rate);
}, [bpm, rate]);
// And the button that controll things
<IconButton
onClick={() => {
handlePlay();
setPlay(!play);
}}
>
{play ? (
<Pause sx={{ fontSize: 60 }} />
) : (
<PlayArrow sx={{ fontSize: 60 }} />
)}
</IconButton>
And guess what!? I can start the metronome, and it works, but:
I can't update dynamically the rate. I mean it updates when I use slider, I console log it, so the rate itself get updated, but not inside metronome function.
When I try to stop the metronome, and when button gets pushed, I see "Timer stoped" in the console, but the function keeps on working.
Things doesn't get updated in the function. What am I missing?

Related

start timer when user click button, React native

I created a function in which when user click start button timer will start, but it's not working. Can someone tell me why it's not working? please
that's the function I created
const [time,setTime] = useState(0)
const timeout = setInterval(() => {
if (time !== 60) {
setTime(prevState => prevState + 1);
}
}, 1000);
console.log(timeout);
return () => {
if (time == 60) {
clearTimeout(timeout);
}
};```
You could declare the Timer State as 60 instead of 0 and
const [state,updateState] = useState({timer:60})
then call this in updateState: ({timer: timer - 1})
To answer your question:
why is my code not working?
Your state timer starts out being 0 and will therefore never reach inside the if statement.
As Matt U pointed out you most likely want to use setInterval since it runs the function you pass at every X milliseconds (1000 in your case) until you stop it.
See the following for more information regarding that:
setTimeout: https://www.w3schools.com/jsref/met_win_settimeout.asp
setInterval: https://www.w3schools.com/jsref/met_win_setinterval.asp
What yesIamFaded answered should do the job in your use case, though it would be better to make use of updateState's argument prevState (or whatever you want to call it). updateState will receive the previous value and use that to compute a new value.
const [state, updateState] = useState({ timer: 60 })
const interval = setInterval(() => {
if (state.timer > 0) {
updateState(prevState => { timer: prevState.timer - 1 });
}
}, 1000);
You can read more about functional updates here:
https://reactjs.org/docs/hooks-reference.html#functional-updates
And lastly, you should clear the timeout and/or interval once you don't need it anymore using either clearTimeout() or clearInterval().
See the following for more information here:
clearTimeout: https://www.w3schools.com/jsref/met_win_cleartimeout.asp
clearInterval: https://www.w3schools.com/jsref/met_win_clearinterval.asp
P.S.
If your timer state isn't coupled with any other state I wouldn't put it into an object. Instead I would do the following:
const [timer, setTimer] = useState(60)
const interval = setInterval(() => {
if (timer > 0) {
setTimer(prevTimer => prevTimer - 1 );
}
}, 1000);
That way you won't have an unnecessary object.

How do I lower a variable by a certain value every second in react

I have this countdown script that I made in react that calculates the time until an event and it works fine, but I want it to recalculate every 1 second to check for updates and such. How do I do this, code inserted below..
const { DateTime } = require("luxon");
// ...
export function GetLaunchCountdown(time) {
// Get launch time
const launchTime = DateTime.fromISO(time.time);
// Get current time
const currentTime = DateTime.now()
// Calculate time difference
const timeDiff = launchTime.diff(currentTime)
const timeDiffMili = timeDiff.toMillis()
var displayTime = DateTime.fromMillis(timeDiffMili)
if (timeDiff.toMillis() > 86400000) {
// Display with days
return(<>{displayTime.toFormat("dd:hh:mm:ss")}</>)
} else {
// Display with hours
return(<>{displayTime.toFormat("hh:mm:ss")}</>)
}
}
// ...
It would be easiest to just subtract from the timeDiffMili variable (that's why it's there).
Store the current time in the state. Use a timing function, like setInterval to change the state. Trigger that timing function inside a useEffect function so that you get a single interval running (and don't start a new one ever rerender). Return a function that clears the interval when the component is unmounted.
const [currentTime, setCurrentTime] = useState(DateTime.now())
useEffect( () => {
const update = () => {
setCurrentTime(DateTime.now());
}
const interval = setInterval(update, 500);
return () => clearInterval(interval);
}, []);

Why useEffect cleanup logging every time?

I'm implementing count down
and use useRef hook to using it when clean setTimeout when the user navigates to the next screen to avoid cancel all subscription warning and it's work!
But I have something weird when count - 1 i can see "hey" in the console! although not cleaning the setTimeOut!!
I don't want to clean it in this case but why should loggin every time count changes!
code snippet
const [seconds, setSeconds] = useState(40);
const countRef = useRef(seconds);
useEffect(() => {
if (seconds > 0) {
countRef.current = setTimeout(() => {
setSeconds(seconds - 1);
}, 1000);
} else {
setSeconds(0);
}
return () => {
console.log('hey'); // every count down it's appeared
clearTimeout(countRef.current);
};
}, [seconds]);
You see "hey" because you're using seconds as a dependency. So every time seconds changes, the effect must run again leading to the effect's destroy function (the function you returned from the effect) to be invoked.
Instead of having seconds as a dependency, you should instead have setSeconds.
const [seconds, setSeconds] = React.useState(10);
useEffect(() => {
let didUnsub = false;
const id = setInterval(() => {
setSeconds((prev) => {
// while the count is greater than 0, continue to countdown
if (prev > 0) {
return prev - 1;
}
// once count eq 0, stop counting down
clearInterval(id);
didUnsub = true;
return 0;
});
}, 1000);
return () => {
console.log("unmounting");
// if the count didn't unsubscribe by reaching 0, clear the interval
if (!didUnsub) {
console.log("unsubscribing");
clearInterval(id);
}
};
}, [setSeconds]);
If you look at the example below, you'll see that the effect is only run once, when the component is mounted. If you were to cause the component to dismount, the destroy function would be invoked. This is because the setState is a dispatch function and doesn't change between renders, therefor it doesn't cause the effect to continuously be called.
In the example you can click the button to toggle between mounting and dismounting the counter. When you dismount it notice that it logs in the console.
Example: https://codesandbox.io/s/gallant-silence-ui0pv?file=/src/Countdown.js

How to use setInterval() and clearInterval() in the same function

I'm trying to create a function that starts and stops a timer. The starting is always on the click of a button, but the stopping can be due to the timer running down or the function being called again from another function.
This is what I have so far. Works perfect for what you see but I cannot figure out how to incorporate clearInterval() so that it stops when the game is won. The functioning calling timerCountdown is located in a different js file. I've read answers to similar questions but they are all seem to be doing it a little differently to where I can't make it work for my case
I do realize that I need to call clearInterval(count) but I don't know how to incorporate this into the function itself.
const timerCountdown = () => {
let count = setInterval(() => {
let timeLeft = timer.innerHTML
if (timeLeft > 0) {
timer.innerHTML = timeLeft - 1
} else {
gameOverMessage()
}
}, 1000)
}
You need to push the interval id in a global variable. Like that you can use another function to stop the interval when you want.
Like
let intervalId; // define `count` globaly
let timer = document.getElementById('timer')
const timerStop = () => {
clearInterval(intervalId)
}
const timerRestart = () => {
timerStop()
timer.innerHTML = 100;
}
const timerStart = () => {
timerStop(); // Stop timer by security, e.g. if you call `timerStart()` multiple times
intervalId = setInterval(() => {
let timeLeft = timer.innerHTML;
if (+timeLeft > 0) {
timer.innerHTML = +timeLeft - 1
} else {
timerRestart();
gameOverMessage()
}
}, 1000)
}
<div id="timer">100</div>
<div>
<button onclick="timerStart()">Start</button>
<button onclick="timerStop()">Pause</button>
<button onclick="timerRestart()">Restart</button>
</div>
setInterval makes a best effort to space the running of the callback according to the interval you specify. The thing is: in a game, what you actually want is the current state of the world to be printed to the screen in smooth and timely fashion. This is different to the behavior of setInterval, which knows nothing about the screen and is blindly called repeatedly.
For example: if you kick-off setInterval(foo, 100) for your game in a browser tab, and then navigate to another tab in your browser, wait ten seconds and then return to your game, your foo callback will be invoked about a hundred times in rapid succession as the queued callbacks are "drained". It is highly unlikely you want this behavior.
requestAnimationFrame is a better solution for this, because it is only called when (shortly before) your game is rendered - which is what you want.
In the following code a timer object is created by createTimer. The timer has start, stop and toggle methods.
The start method records when it was invoked and triggers requestAnimationFrame, supplying a callback called tick. Every time a tick occurs, we run some logic to see which (if any) callback to invoke.
If the time elapsed is greater than or equal to the duration of the timer, then the onTimeout callback is invoked and the timer is stopped.
If the time elapsed is smaller than the duration, but greater than or equal to the interval period, then we update the lastInterval and invoke the onInterval callback.
Otherwise we simply cue up another tick of the timer.
The stop method simply uses the request animation ID to cancel the timer with cancelAnimationFrame.
function createTimer() {
let rafId = null
function start({duration = 10000, interval = 1000, onInterval, onTimeout, onStop, startTime=performance.now(), lastInterval = startTime}) {
function tick(now=performance.now()) {
const elapsed = now - startTime
if (elapsed >= duration) {
cancelAnimationFrame(rafId)
rafId = null
return onTimeout()
}
if ((now - lastInterval) >= interval) {
lastInterval = now
onInterval({
duration,
elapsed
})
}
rafId = requestAnimationFrame(tick)
}
rafId = requestAnimationFrame(tick)
}
function stop() {
cancelAnimationFrame(rafId)
rafId = null
return onStop()
}
function toggle(...args) {
rafId ? stop() : start(...args)
}
const timer = {
start,
stop,
toggle
}
return timer
}
const timer = createTimer()
const onInterval = ({duration, elapsed})=>console.log(`Remaining: ${((duration - elapsed)/1000).toFixed(0)}`)
const onTimeout = ()=>console.log('Timed out.')
const onStop = ()=>console.log('Manually stopped.')
document.getElementById('btn').addEventListener('click', () => timer.toggle({
onInterval,
onTimeout,
onStop
}))
<button id="btn">Toggle Timer</button>
You could take a global variable intervalId and clear the interval timer, if won or if no time is avaliable.
var intervalId;
const timerCountdown = () => {
intervalId = setInterval(() => {
let timeLeft = timer.innerHTML
if (timeLeft > 0) {
timer.innerHTML = timeLeft - 1
} else {
clearInterval(intervalId);
gameOverMessage();
}
}, 1000)
},
won = () => {
clearInterval(intervalId);
// additional code
};

find the time left in a setTimeout()?

I'm writing some Javascript that interacts with library code that I don't own, and can't (reasonably) change. It creates Javascript timeouts used for showing the next question in a series of time-limited questions. This isn't real code because it is obfuscated beyond all hope. Here's what the library is doing:
....
// setup a timeout to go to the next question based on user-supplied time
var t = questionTime * 1000
test.currentTimeout = setTimeout( showNextQuestion(questions[i+1]), t );
I want to put a progress bar onscreen that fills towards questionTime * 1000 by interrogating the timer created by setTimeout. The only problem is, there seems to be no way to do this. Is there a getTimeout function that I'm missing? The only information on Javascript timeouts that I can find is related only to creation via setTimeout( function, time) and deletion via clearTimeout( id ).
I'm looking for a function that returns either the time remaining before a timeout fires, or the time elapsed after a timeout has been called. My progress bar code looks like this:
var timeleft = getTimeout( test.currentTimeout ); // I don't know how to do this
var $bar = $('.control .bar');
while ( timeleft > 1 ) {
$bar.width(timeleft / test.defaultQuestionTime * 1000);
}
tl;dr: How do I find the time remaining before a javascript setTimeout()?
Here's the solution I'm using now. I went through the library section that's in charge of tests, and unscrambled the code (terrible, and against my permissions).
// setup a timeout to go to the next question based on user-supplied time
var t = questionTime * 1000
test.currentTimeout = mySetTimeout( showNextQuestion(questions[i+1]), t );
and here's my code:
// wrapper for setTimeout
function mySetTimeout( func, timeout ) {
timeouts[ n = setTimeout( func, timeout ) ] = {
start: new Date().getTime(),
end: new Date().getTime() + timeout
t: timeout
}
return n;
}
This works pretty spot-on in any browser that isn't IE 6. Even the original iPhone, where I expected things to get asynchronous.
Just for the record, there is a way to get the time left in node.js:
var timeout = setTimeout(function() {}, 3600 * 1000);
setInterval(function() {
console.log('Time left: '+getTimeLeft(timeout)+'s');
}, 2000);
function getTimeLeft(timeout) {
return Math.ceil((timeout._idleStart + timeout._idleTimeout - Date.now()) / 1000);
}
Prints:
$ node test.js
Time left: 3599s
Time left: 3597s
Time left: 3595s
Time left: 3593s
This doesn't seem to work in firefox through, but since node.js is javascript, I thought this remark might be helpful for people looking for the node solution.
EDIT: I actually think I made an even better one: https://stackoverflow.com/a/36389263/2378102
I wrote this function and I use it a lot:
function timer(callback, delay) {
var id, started, remaining = delay, running
this.start = function() {
running = true
started = new Date()
id = setTimeout(callback, remaining)
}
this.pause = function() {
running = false
clearTimeout(id)
remaining -= new Date() - started
}
this.getTimeLeft = function() {
if (running) {
this.pause()
this.start()
}
return remaining
}
this.getStateRunning = function() {
return running
}
this.start()
}
Make a timer:
a = new timer(function() {
// What ever
}, 3000)
So if you want the time remaining just do:
a.getTimeLeft()
If you can't modify the library code, you'll need to redefine setTimeout to suit your purposes. Here's an example of what you could do:
(function () {
var nativeSetTimeout = window.setTimeout;
window.bindTimeout = function (listener, interval) {
function setTimeout(code, delay) {
var elapsed = 0,
h;
h = window.setInterval(function () {
elapsed += interval;
if (elapsed < delay) {
listener(delay - elapsed);
} else {
window.clearInterval(h);
}
}, interval);
return nativeSetTimeout(code, delay);
}
window.setTimeout = setTimeout;
setTimeout._native = nativeSetTimeout;
};
}());
window.bindTimeout(function (t) {console.log(t + "ms remaining");}, 100);
window.setTimeout(function () {console.log("All done.");}, 1000);
This is not production code, but it should put you on the right track. Note that you can only bind one listener per timeout. I haven't done extensive testing with this, but it works in Firebug.
A more robust solution would use the same technique of wrapping setTimeout, but instead use a map from the returned timeoutId to listeners to handle multiple listeners per timeout. You might also consider wrapping clearTimeout so you can detach your listener if the timeout is cleared.
Server side Node.js specific
None of the above really worked for me, and after inspecting the timeout object it looked like everything was relative to when the process started. The following worked for me:
myTimer = setTimeout(function a(){console.log('Timer executed')},15000);
function getTimeLeft(timeout){
console.log(Math.ceil((timeout._idleStart + timeout._idleTimeout)/1000 - process.uptime()));
}
setInterval(getTimeLeft,1000,myTimer);
Output:
14
...
3
2
1
Timer executed
-0
-1
...
node -v
v9.11.1
Edited output for brevity, but this basic function gives a approximate time until execution or since execution. As others mention, none of this will be exact due to the way node processes, but if I want to suppress a request that was run less than 1 minute ago, and I stored the timer, I don't see why this wouldn't work as a quick check. Could be interesting to juggle objects with refreshtimer in 10.2+.
Javascript's event stacks don't operate how you would think.
When a timeout event is created, it is added to the event queue, but other events may take priority while that event is being fired, delay the execution time and postponing runtime.
Example: You create a timeout with a delay of 10 seconds to alert something to the screen. It will be added to the event stack and will be executed after all current events are fired (causing some delay). Then, when the timeout is processed, the browser still continues to capture other events add them to the stack, which causes further delays in the processing. If the user clicks, or does a lot of ctrl+typing, their events take priority over the current stack. Your 10 seconds can turn into 15 seconds, or longer.
That being said, there are many ways to fake how much time has passed. One way is to execute a setInterval right after you add the setTimeout to the stack.
Example: Perform a settimeout with a 10 second delay (store that delay in a global). Then perform a setInterval that runs every second to subtract 1 from the delay and output the delay remaining. Because of how the event stack can influence actual time (described above), this still won't be accurate, but does give a count.
In short, there is no real way to get the remaining time. There are only ways to try and convey an estimate to the user.
A quicker, easier way:
tmo = 1000;
start = performance.now();
setTimeout(function(){
foo();
},tmo);
You can get the time remaining with:
timeLeft = tmo - (performance.now() - start);
I stopped by here looking for this answer, but was overthinking my problem. If you are here because you just need to keep track of time while you're setTimeout is in progress, here's another way to do it:
var focusTime = parseInt(msg.time) * 1000
setTimeout(function() {
alert('Nice Job Heres 5 Schrute bucks')
clearInterval(timerInterval)
}, focusTime)
var timerInterval = setInterval(function(){
focusTime -= 1000
initTimer(focusTime / 1000)
}, 1000);
You can modify setTimeout to store each timeout's end time in a map and create a function called getTimeout to get the time left for a timeout with a certain id.
This was super's solution, but I modified it to use slightly less memory
let getTimeout = (() => { // IIFE
let _setTimeout = setTimeout, // Reference to the original setTimeout
map = {}; // Map of all timeouts with their end times
setTimeout = (callback, delay) => { // Modify setTimeout
let id = _setTimeout(callback, delay); // Run the original, and store the id
map[id] = Date.now() + delay; // Store the end time
return id; // Return the id
};
return (id) => { // The actual getTimeout function
// If there was no timeout with that id, return NaN, otherwise, return the time left clamped to 0
return map[id] ? Math.max(map[id] - Date.now(), 0) : NaN;
}
})();
Usage:
// go home in 4 seconds
let redirectTimeout = setTimeout(() => {
window.location.href = "/index.html";
}, 4000);
// display the time left until the redirect
setInterval(() => {
document.querySelector("#countdown").innerHTML = `Time left until redirect ${getTimeout(redirectTimeout)}`;
},1);
Here's a minified version of this getTimeout IIFE:
let getTimeout=(()=>{let t=setTimeout,e={};return setTimeout=((a,o)=>{let u=t(a,o);return e[u]=Date.now()+o,u}),t=>e[t]?Math.max(e[t]-Date.now(),0):NaN})();
I hope this is as useful to you as it was for me! :)
No, but you can have your own setTimeout/setInterval for animation in your function.
Say your question looks like this:
function myQuestion() {
// animate the progress bar for 1 sec
animate( "progressbar", 1000 );
// do the question stuff
// ...
}
And your animation will be handled by these 2 functions:
function interpolate( start, end, pos ) {
return start + ( pos * (end - start) );
}
function animate( dom, interval, delay ) {
interval = interval || 1000;
delay = delay || 10;
var start = Number(new Date());
if ( typeof dom === "string" ) {
dom = document.getElementById( dom );
}
function step() {
var now = Number(new Date()),
elapsed = now - start,
pos = elapsed / interval,
value = ~~interpolate( 0, 500, pos ); // 0-500px (progress bar)
dom.style.width = value + "px";
if ( elapsed < interval )
setTimeout( step, delay );
}
setTimeout( step, delay );
}
If anyone's looking back on this. I've come out with a timeout and interval manager that can get you the time left in a timeout or interval as well as do some other stuff. I'll be adding to it to make it more nifty and more accurate, but it seems to work fairly well as is (although I have some more ideas to make it even more accurate):
https://github.com/vhmth/Tock
Question has already been answered but I will add my bit. It just occured to me.
Use setTimeout in recursion as follows:
var count = -1;
function beginTimer()
{
console.log("Counting 20 seconds");
count++;
if(count <20)
{
console.log(20-count+"seconds left");
setTimeout(beginTimer,2000);
}
else
{
endTimer();
}
}
function endTimer()
{
console.log("Time is finished");
}
I guess the code is self explanatory
Check this one:
class Timer {
constructor(fun,delay) {
this.timer=setTimeout(fun, delay)
this.stamp=new Date()
}
get(){return ((this.timer._idleTimeout - (new Date-this.stamp))/1000) }
clear(){return (this.stamp=null, clearTimeout(this.timer))}
}
Make a timer:
let smtg = new Timer(()=>{do()}, 3000})
Get remain:
smth.get()
Clear timeout
smth.clear()
(function(){
window.activeCountdowns = [];
window.setCountdown = function (code, delay, callback, interval) {
var timeout = delay;
var timeoutId = setTimeout(function(){
clearCountdown(timeoutId);
return code();
}, delay);
window.activeCountdowns.push(timeoutId);
setTimeout(function countdown(){
var key = window.activeCountdowns.indexOf(timeoutId);
if (key < 0) return;
timeout -= interval;
setTimeout(countdown, interval);
return callback(timeout);
}, interval);
return timeoutId;
};
window.clearCountdown = function (timeoutId) {
clearTimeout(timeoutId);
var key = window.activeCountdowns.indexOf(timeoutId);
if (key < 0) return;
window.activeCountdowns.splice(key, 1);
};
})();
//example
var t = setCountdown(function () {
console.log('done');
}, 15000, function (i) {
console.log(i / 1000);
}, 1000);
For anyone in need of a hook, check this out - should be pretty self explanatory.
Note that elapsed is an internal state variable that if passed outside of the hook will be incorrect!
import { useEffect, useRef, useState } from 'react';
const useTimeout = (callback, duration, renderDuration = 5) => {
const ref = useRef<any>(null);
const [timeInfo, setTimeInfo] = useState<{
start: number;
elapsed: number;
percentComplete: number;
}>({
start: null,
elapsed: 0,
percentComplete: 0
});
useEffect(() => {
return () => {
if (ref.current) {
clearTimeout(ref.current);
ref.current = null;
}
};
}, []);
useEffect(() => {
setTimeout(() => {
if (ref.current == null) return;
setTimeInfo((prev) => {
const elapsed = Date.now() - prev.start + prev.elapsed;
if (ref.current == null) return prev;
return {
start: prev.start,
elapsed: prev.elapsed,
percentComplete: (elapsed / duration) * 100
};
});
}, renderDuration);
}, [timeInfo]);
return {
percentComplete: timeInfo.percentComplete,
isTimerRunning: ref.current != null,
startTimeout: () => {
if (ref.current != null) return;
setTimeInfo((prev) => ({ ...prev, start: Date.now() }));
ref.current = setTimeout(callback, duration - timeInfo.elapsed);
},
stopTimeout: () => {
if (ref.current) {
clearTimeout(ref.current);
ref.current = null;
}
setTimeInfo((prev) => {
const elapsed = Date.now() - prev.start + prev.elapsed;
return {
start: prev.start,
elapsed: elapsed,
percentComplete: (elapsed / duration) * 100
};
});
},
resetTimeout: () => {
if (ref.current) {
ref.current = null;
clearTimeout(ref.current);
}
setTimeInfo({ start: null, elapsed: 0, percentComplete: 0 });
},
restartTimeout: () => {
if (ref.current) {
ref.current = null;
clearTimeout(ref.current);
}
setTimeInfo({ start: Date.now(), elapsed: 0, percentComplete: 0 });
ref.current = setTimeout(callback, duration);
}
};
};
export default useTimeout;

Categories