loading...
Cover image for Project 14 of 100 - React Countdown Clock

Project 14 of 100 - React Countdown Clock

jwhubert91 profile image James Hubert ・3 min read

Hey! I'm on a mission to make 100 React.js projects in 100 days starting October 31, 2020 and ending February 7th, 2021. Please follow my dev.to profile or my twitter for updates and feel free to reach out if you have questions. Thanks for your support!

Link to today's deployed app: link
Link to the repo: github

Today I implemented key pieces (including CSS) from Chris Bongers' recent article on setInterval in Javascript. Although the styling and second/hour/minute/day conversions are borrowed from his article, there were significant changes that had to be made to accommodate React.

The App

I don't think there's a single JS programmer anywhere who hasn't wrestled with setTimeout and setInterval, and with the JS Date object.

It's true that creating a universal time for all offline computers must have been hard. But measuring all browser time in seconds from an arbitrary day in 1970?

Usually working with the native JS date functions involves a lot of converting and comparing of formats and values so it's always a good thing to gain practice in. Also, Chris Bongers' solution to a countdown timer was rather elegant in how easily it solved the infamous problem of drift using the built-in JS Date methods.

Time & State

In Chris' example, the html elements are selected via id's and he uses document.getElementById() to force update each element with a new value each second as the countdown goes on.

In React, the best way to do this is by setting state as the time changes. This will make each new time value available to the component and will communicate these values to the JSX elements as state changes with each second.

this.setState({ daysLeft: Math.floor(difference / days) });
this.setState({ hoursLeft: Math.floor((difference % days) / hours) });
this.setState({ minutesLeft: Math.floor((difference % hours) / minutes)});
this.setState({ secondsLeft: Math.floor((difference % minutes) / seconds)});
Enter fullscreen mode Exit fullscreen mode

It would have probably been more graceful to simply store the now value in state and each time it changed read it and make the conversion within the render() method. But I wanted a little practice, so this works as well.

Solution for setInterval Drift

Chris doesn't even mention it in his article, but the reason his little timing function is so long is that rather than simply calculate a time difference once and feed that number into a setTimeout function, which over days would accumulate quite a bit of inaccuracy, instead he continually calculates the difference and displays that after converting.

Again, it may be unnecessary but I stored these values in state each time just to keep track:

this.setState({ now: new Date().getTime() });
this.setState({ end: new Date('January 20, 2021 00:00:00').getTime() });
const difference = this.state.end - this.state.now;
Enter fullscreen mode Exit fullscreen mode

setInterval can drift when there are lots of processes running on your machine or browser, when you close your laptop and open it, or for any number of other reasons. In a pure JS Pomodoro app I made a while ago link even in 25 minutes I noticed the timer was at times inaccurate.

Takeaways

Working with Dates isn't the most exciting thing but it's something most applications require so it's good to get practice where you can.

React once again provides an elegant way of containing all of the counter functionality to a single Javascript component within the page.

Thanks for reading!

Discussion

pic
Editor guide