How to Build a Productivity Application in React: Part 4

Creating a Pomodoro Timer

As I said in Part 1 of this tutorial, the motivation behind creating this series was my desire to build a Pomodoro timer. I love the Pomodoro technique (no, this isn’t an ad!), especially because it keeps me on track as someone who is taking online classes while also working remotely full-time.

So, in Part 4 of our tutorial, we’re going to build a small countdown timer! This timer will start out with 25 minutes on the clock (the standard chunk of time for Pomodoro working). When it reaches 0, the timer will reset to 5 minutes and start counting down for your break. After those five minutes is up, the cycle will restart! And, because no one is perfect, we’ll add in the functionality to start and pause the timer.

If you’re following along with the series, it’s good to have you back! If you’re joining us for the first time and you’d like to see the previous material, check out parts 1, 2, and 3, and head over to the GitHub repository to see previous code.

Setting Up Our Pomodoro Timer

Let’s start by setting up our application to receive our timer functionality. First, we’re going to head into App.js and place some key-value pairs on our state. If you remember, we already have key-value pairs for todos and todo. Here, we’re going to add:

restMinutes to represent the 5-minute break interval, set to 5.

workMinutes to represent the 25-minute work period, set to 25.

seconds to represent the countdown between whole minutes, set to 0. (Think about it this way: you’ll start with 25 minutes and 0 seconds, then our timer will move to 24 minutes and 59 seconds, 58 seconds, 57 seconds… so we have to start with 0.

break is a boolean telling your application whether or not it should be displaying restMinutes. We’ll start with it set to false, because I’m assuming you aren’t starting your day with a break!

start is a boolean that functions as the opposite of break. It tells the application whether or not it should be displaying workMinutes. We’ll also start with this set to false, so that your timer doesn’t begin as soon as you load the application, and give it a Start Button to begin your timer.

interval is going to refer to the period of time between the actions of your timer. Your timer changing its countdown is considered an action, and will be completed on a set interval of milliseconds, which will later be added to your browser and then cleared. We’ll get into this more later!

Let’s also quickly set up our Pomodoro.js file inside of our components directory with a functional component. We won’t be manipulating state in this file, because we’ll be keeping all of our functions inside of our App.js file. We will, however, pass in props. We’ll need props to keep track of our break/start toggle, as well as our restMinutes, workMinutes, and seconds.

The functional component will return a paragraph tag, where we’ll put our countdown timer, starting at 25:00. Below that is our button, which will switch between Pause and Start based on our state.

Now, before we start on our timer functionality, go ahead and import your Pomodoro component in App.js and add it to our App class component.

Building Our Pomodoro Timer Functionality

Let’s start in on our timer functionality. First, build a function in the App component called timer. The first thing we’ll do inside of our timer function is set the state for our seconds. This is the most basic part of our timer: the seconds on our state will start at 0, move to 59, and count down to 0 again. Once our timer hits zero, the seconds will reset. We’ll build in this functionality using a ternary operation like the one below.

If you’re not familiar with ternary operators, check out the MDN documentation, as well as some great articles here, and here. Ternary operators are essentially conditional statements that run code in a similar way to if/else statements. Personally, I like to use them in situations where it makes sense to keep a line short. I often use if/else statements when the code executed within them is more complicated. Hence, you’ll see me use both throughout this tutorial.

Handling the minute functionality will be slightly more complicated. We’ll need to start with an if statement checking to see whether or not break is set to true or false. If it’s set to true, we’ll setState on our minutes, checking against our seconds for whether or not to subtract a minute from our overall tally. We’ll do this using a series of ternary operations again:

After this, we’ll add in another if statement. If the previous if statement returns -1 for restMinutes, we’ll reset break to false, and reset restMinutes to 5. This statement will start our workMinutes as well.

Lastly for this functionality, we’ll add in the same logic under an else statement to flesh out the same countdown for the workMinutes. The nested if statement will also take care of a reset, pushing workMinutes back to 25 and break to true.

Finally, let’s pass all of the props necessary for our Pomodoro timer in our App.js file and render our timer. Inside the render function of our App component, pass our timer function and our other related items on state to the Pomodoro component.

Then, we’ll use a ternary function inside of our Pomodoro.js file to display the timer minutes and numbers correctly. This function accounts for numbers below ten; when under ten, a 0 will display in front of the seconds count.

At this point, you should be able to head into your local server and view a paused timer that reads 25:00. Next, let’s add the start and pause functionality to our timer.

Start and Pause Functionality

Head into App.js and add a function (mine’s called startTimer). Inside of our function, we’ll setState to update our interval and start key-value pairs. Interval will have the setInterval method, which takes in a function and a number that represents milliseconds. Additionally, we’ll update start to flip its boolean value to the opposite of its current state.

Now we’ll add in another function to pause the timer (again, unsurprisingly, mine’s called pauseTimer). Our pause functionality is going to take advantage of prevState, like we did in our removeItems function. Based on the previous state of the timer, we’ll return a static version of our items on state. Start will be set to false (because we’re on a break), and the interval will clear using clearInterval to stop the action of the timer.

Now, let’s pass these functions to our button in the Pomodoro component. In our render function in the App component, let’s pass the functions as props:

Now, in our Pomodoro.js file, we’ll set up our button. First, we’ll add an onClick method that uses a ternary operator to check whether or not props.start is set to true. If it is, the onClick function will be our pauseTimer function. If it is set to false, the onClick function will be our startTimer function. Then, we’ll also use a ternary operator to change the text of the button to read Pause or Start depending on whether or not props.start is set to true.

Congratulations! You’ve completed your timer. Feel free to play around with the times, or create separate buttons for pausing and starting. Make sure you understand each of the ternary operators, since they can often be confusing.