Timers are very commonly used in React for all sorts of applications. They allow you to manipulate the order in which events occur.
From the React Native Timer documentation, there are four types of timers:
- Timeout (delay)
- Interval (repeat with interval)
- Immediate (call as soon as possible)
- Animation (call when the browser is ready to render frame)
In this article, we will go over all four-timer types, and their methods, in detail.
Table of Contents
Why the React Native Timer?
The React Native Timer is actually an implementation of the vanilla JavaScript timer, sharing the same methods.
Usually, code runs synchronously, or one line at a time, where a line only executes when the previous line has already been completed. However, it’s often much better to run code asynchronously, or based on conditions rather than a predefined order.
With the React Native Timer, we can run blocks of code asynchronously in set time periods.
Take a look at the code below, which uses the setTimeout() method to run asynchronously.
function TimerComponent() {
setTimeout(() => {
console.log("2 sec.")
}, 2000);
setTimeout(() => {
console.log("1 sec.")
}, 1000);
console.log("no timer.")
return (
<div>
Hello World
</div>
)
}
export { TimerComponent }
When the above code is run, this output is generated in the console:
As you can see, the output is generated in the opposite order of what would happen in ordinary synchronous code.
Why do “1 sec.” and “2 sec.” each run twice? Glad you asked.
Using ‘useEffect’ with React Native Timer
React is often run in Strict Mode, which alters React’s development mode (what you’d usually run in your browser). One of the changes this brings is that your code will be run twice to better highlight potential errors.
Usually, console.log() is suppressed from running twice, but since in this case we are running it within a setTimeout(), the React compiler fails to suppress the second execution.
To avoid this bug, we use useEffect. Any code run with useEffect is only executed once when the React component is being rendered to the screen:
import { useEffect } from 'react'
function TimerComponent() {
setTimeout(() => {
console.log("2 sec.")
}, 2000);
useEffect(() =>; {
setTimeout(() =>; {
console.log('1 sec.');
}, 1000);
return () =>; {
clearTimeout(timer);
}
}, []);
return (
<div>
Hello World
</div>
)
}
export { TimerComponent }
Output in the console:
As you can see, “1 sec.”, which was run within useEffect, was only printed to the console once, whereas “2 sec.”, which was run normally within React Strict Mode, was printed twice.
Now that we’ve gotten that out of the way, we will go through all the React Timer functions.
Difference Between setTimeout vs clearTimeout
setTimeout() sets a block of code to run on a delay, while clearTimeout() removes the task, preventing it from running at all. We’ll see this in action:
import { useEffect } from 'react'
function TimerComponent() {
useEffect(() =>; {
setTimeout(() =>; {
console.log("2 sec.")
}, 2000);
var oneSec = setTimeout(() =>; {
console.log('1 sec.');
}, 1000);
clearTimeout(oneSec)
}, []);
return (
<div>
Hello World
</div>
)
}
export { TimerComponent }
When run, the code produces the following output in the console :
While “1 sec.” was originally supposed to print before “2 sec.”, clearTimeout() made it not print at all.
Note that we set the variable oneSec. setTimeout() returns the ID needed in order to be able to reference the timeout later in clearTimeout.
Using setInterval and clearInterval
setInterval() and clearInterval() are similar to setTimeout() and clearTimeout(), but the difference is that they run multiple times.
Interval means that the code is run over and over again with a predefined time period between each execution. We’ll see an example below.
Read the full write-up on how to use setInterval.
import { useEffect } from 'react'
function TimerComponent() {
useEffect(() =>; {
setTimeout(() =>; {
console.log("2 sec.")
}, 2000);
setInterval(() =>; {
console.log('1 sec.');
}, 1000);
}, []);
return (
<div>
Hello World
</div>
)
}
export { TimerComponent }
After running for a bit, the code produces the following output in the console:
As you can see, setInterval() operates like setTimeout() but with a forever repeating loop around it. This means that the function specified to execute can run indefinitely.
What if we want to get rid of the interval execution after a certain number of executions? That’s where clearInterval() comes in:
import { useEffect } from 'react'
function TimerComponent() {
useEffect(() =>; {
var counter = 0;
var oneSecInterval = setInterval(() =>; {
console.log('1 sec.');
counter ++;
if (counter == 5) {
clearInterval(oneSecInterval);
}
}, 1000);
}, []);
return (
<div>
Hello World
</div>
)
}
export { TimerComponent }
When the counter reaches 5, clearInterval() is called, removing the interval from the program. Thus, the output of this code in the console is:
After five executions, the interval is terminated.
setImmediate and clearImmediate
setImmediate runs code asynchronously as soon as possible. This means that the specified code will run immediately on the next iteration of the event loop (after the browser has handled events and display updates.
setImmediate() is best shown with an example:
import { useEffect } from 'react'
function TimerComponent() {
useEffect(() => {
console.log("1");
setImmediate(() => {
console.log('Immediate.');
});
console.log("2");
}, []);
return (
<div>
Hello World
</div>
)
}
export { TimerComponent }
Outputs in the console:
In the example above, setImmediate runs immediately after “1” and “2” are logged to the console. We can think of setImmediate as being very similar to setTimeout where the delay amount is 0.
As always, setImmediate has its corresponding clearing function, clearImmediate:
import { useEffect } from 'react'
function TimerComponent() {
useEffect(() => {
console.log("1");
var immediate = setImmediate(() => {
console.log('Immediate.');
});
clearImmediate(immediate);
console.log("2");
}, []);
return (
<div>
Hello World
</div>
)
}
export { TimerComponent }
Outputs in the console:
requestAnimationFrame() and clearAnimationFrame()
requestAnimationFrame() is used to fire a function only after all frames have been flushed, and before the next animation sequence begins. This is useful, for example, when you are updating values in between frames.
For example, when constantly updating an object:
import { useState } from 'react'
function TimerComponent() {
const [number, setNumber] = useState(0);
var increment = function () {
setNumber(number+1);
requestAnimationFrame(increment);
};
requestAnimationFrame(increment);
return (
<div>
{number}
</div>
)
}
export { TimerComponent }
In the code example above, we constantly increase number through setNumber, which is created by useState. To do so, we use a recursive loop.
requestAnimationFrame(increment) first gets the recursive loop going, calling the increment function in between rendering frames. The function increment then calls itself over and over again, continuously increasing ‘number’.
The magic is in the requestAnimationFrame. The function ensures that the update of number happens in between renders of the screen.
This is extremely important because it ensures that the incrementing of ‘number’ is done as expected, instead of happening randomly. Without requestAnimationFrame(), number is likely to be incremented while the frame is re-rendering itself, causing inconsistencies.
clearAnimationFrame() works as we expect:
import { useState } from 'react'
function TimerComponent() {
const [number, setNumber] = useState(0);
var increment = function () {
setNumber(number+1);
var animationUpdate = requestAnimationFrame(increment);
if (number >= 500) {
clearAnimationFrame(animationUpdate)
}
};
requestAnimationFrame(increment);
return (
<div>
{number}
</div>
)
}
export { TimerComponent }
In the example above, the requestAnimationFrame() is cleared after number has been incremented above 500.
Thank you for following through this article, and I hope you now know how to use the React Native Timer!
💬 Leave a comment