Creating a Lap Timer in React
Nolan Miller
Posted on July 24, 2024
Another late night with lofi music plaing in my office working on Roast.
Not quite so late as last night, and I spent a good amount of time tonght doing housework, but I made a lot of progress this morning and in my session tonight!
The Output
The work today, is the second page in the roast flow. This the meat of the front end functionality. It’s the screen where you actually do the roasting!
I’m very happy with how the animations turned out. The solution was conditionally changing colors, background colors, and font sizes based on the step
state that I had already implemented!
The hardest part of this was doing pixel calculations to figure out how to get the size changes to not bounce the whole UI all over the place.
Making a Working Lap Timer
While this is an app for roasting coffee, the functionality is essentially a lap timer for a stop watch. This one functions by setting a value within the Roast
instance and displaying that value on screen when the “Record Step" button is playing.
Here’s everything I had to implement to make this work for my project. You will be able to see how this applies to other types of time recording.
Create an Object to Store The Data to Display
I chose to create a class for my Roasts so that I can create them more easily throughout the application. Below, I’ve omitted some of the properties from the constructor for clarity:
// roasts.js
class Roast {
constructor(date) {
// other roast properties
this.tempRiseSeconds = null
this.firstCrackSeconds = null
this.tempRiseSeconds = null
this.openedLidSeconds = null
this.heatOffSeconds = null
this.dumpedSeconds = null
}
}
The actual object will be created in the next step.
Handle the Records
If you’d like more information on the timer, and the flow of the application, take a look at the past few days in this series. I have attached the start()
function of my timer module to the flow of the application.
Although the data is displayed to the user in a component called Status.js
, I've chosen to control the data within its parent component, Roaster.js
.
Notice that the roast
object, an instance of Roast
is passed into the Roaster
as a prop along with its setter. In the next component up, the state of this roast object is being managed, since it will be saved to the library once the Roaster component is unmounted.
// Roaster.js
// imports ...
const Roaster = ({ roast, setRoast }) => {
// State to move through the roast process
const [progress, setProgress] = useState("start-roast-form");
const [roastStep, setRoastStep] = useState(1);
// Timer module mount
const { time, start, pause, reset, status} = useTimer();
const nextProgress = () => { /* Application flow logic */ }
const nextStep = () => { /* Push roast to the next roastStep */ }
// Log the roast timing
const logTime = () => {
let key = '';
if (roastStep === 1) key = 'firstCrackSeconds'
if (roastStep === 2) key = 'tempRiseSeconds'
if (roastStep === 3) key = 'openedLidSeconds'
if (roastStep === 4) key = 'heatOffSeconds'
if (roastStep === 5) key = 'dumpedSeconds'
setRoast(prev => ({
...prev,
[key]: time
}))
}
// Moves to next step and logs the time
const handleRecordStep = () => {
logTime();
nextStep();
}
}
The key here, is the logTime
function, which copies the state from the previous state of the roast
object passed in, and then dynamically sets the proper key to the current time of the stopwatch.
The logic is then packaged with the nextStep()
function in handleRecordStep()
.
It turns out, it's not too complex to log real-time events using a timer in React. Hope it helps with a future project!
Check Out the Repo
If you want to keep up with the changes, fork and run locally, or even suggest code changes, here’s a link to the GitHub repo!
Posted on July 24, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.