How To Create A Unique Workout Planner With ReactJS

Colton Kaiser
9 min readNov 9, 2020

--

Recently, a leading athletic performance technology company told me they have a bit of a market gap in terms of keeping up with the competition. Currently, they offer a very effective way to track the performance of athletes, but they don’t have anything that tells coaches and athletes how to plan their workouts based on this information.

More and more companies are starting to emerge that create workout programs for teams, so they decided it’s time to implement something like this into their business model.

Coming from a heavy background as a strength and conditioning coach before I was a software engineer, I decided I was in a unique position to take this information and create something that could lead them in the right direction.

In this article, I’ll go over the step by step process of how I created this application.

A quick side note that you probably don’t care about and can skip

Velocity Based Training (VBT), is a means of strength training for athletes. More and more research/practical experience amongst strength and conditioning coaches is showing that weight training programs based on 1 Rep Max (1RM) are not very effective and can actually be counterintuitive. There are many reasons for this thought process but here’s a main few:

  • Individual strength fluctuates day-to-day. An athlete’s 1RM one day could be drastically different the next. There are many factors for this but the main point here is that this makes 1RM an unreliable means to base programs off of. VBT takes this into account as main exercises are based on velocity on the day-to-day.
  • It doesn’t matter how strong an athlete is if they aren’t fast. VBT allows strength and conditioning coaches to base their weight training programs off of speed, rather than an arbitrary amount of weight. Not only this, but it allows them to have an actual metric of speed rather than just telling their athletes to “move the bar fast”.
  • Most VBT softwares show the athlete their speed in real-time. This results in increased motivation, competition, and fun during workouts.

This all being said, I want to be very clear. This article does NOT require any sort of knowledge of fitness, sports, strength training, etc. It does require basic/intermediate knowledge of ReactJS, some knowledge of React Hooks, JavaScript syntax, and basic CSS.

Now, back to our regularly scheduled programming (no pun intended)

This application is a Single Page ReactJS application that utilizes Material-UI and a bit of custom CSS.

Here’s what it will look like:

If you’re wondering where the speed data is coming from, here’s the chart our VBT metrics in this application will be based on. Again, if you don’t understand this, don’t worry as it’s not expected or important. This is only for you to see what the data is based on.

Source: https://drivelinebaseball.com

Let’s first briefly create our user stories.

User Stories

User will be able to:

  • Select a workout day from a dropdown menu
  • Select their velocity from last month
  • Have the information be populated in a table based on this information

We’re going to be using the React UI framework, Material-UI, to create our dropdown menus and table.

We install this by entering npm i @material-ui/core into the terminal.

The Data

For this to be a hosted SPA (Single Page Application) that didn’t require a backend, I created a small data file with information that will be pulled into the table cells. We export these three arrays of objects in one Data object at the bottom of the file.

Yes, this information is hardcoded and would not be like this in a full-fledged commercial application (as opposed to pulling from an API, user input, etc.). For now, this data is used specifically to keep our application simple.

App level component

Since we’re using hooks for this app, we’ll need to import useState from React. We're also going to be creating the day dropdown menu from this level, so we'll need to import the TextField and MenuItem components from Material-UI. Form is a folder created to house our velocity dropdown menu.

Next, since we’re going to need to tell our app which day it should use to populate the exercises on the table. We’ll handle that as state on the App level.

We’ll pass this information down to our Form component as props.

Next, let’s create a changeDay() function that sets our state based on the value of what was clicked in the dropdown (either "Upper Body" or "Lower Body").

Lastly, we need to create our Day dropdown menu using Material-UI. Then have our changeDay() function each time an option is clicked. Thus setting the day state to whichever option is selected (remember this is being passed down to our Form component, which we will get to next).

Here’s what we get:

Here’s what our file looks like:

Velocity dropdown form component

Let’s do our imports first. We’ll need useState and useEffect from React, our workout/velocity data from our Data file, a WorkoutTable component that we will render here and pass down props to, and the TextField and MenuItem components from Material-UI.

We’ll need the day prop that we passed down from the app level, and we'll also need to have our velocity range string (for the table) and velocity name string (for the title of the phase) as state. We'll then pass these down to the table component.

Let’s create a function similar to the one on the App level that takes the selection from the menu and sets it as state.

Now we’ll create our dropdown. Similar to the app level, we’ll need to call our changeVelocity() function any time a new option is clicked. We'll also need to set the velocity ranges as choices in the dropdown menu.

Here’s what we’re left with:

We’re still left with another task. We need to handle retrieving the name of the velocity phase from the object relative to what was selected from the dropdown menu so we can make that the title of the chart when it’s populated.

We’ll handle this by creating a function called getVelocityName() that filters through the Velocities array from our Data file and finds/returns the object that has the same range value as the one that has been selected in the dropdown menu. Then set this to be our velocityName state so we can pass it down as props to the table component.

But there’s a problem. We need this to happen each time another option is clicked, not just on initial render. We’ll use useEffect for this and set its dependency array to the velocityRange state. This way, any time the velocityRange state is updated due to an option being selected, so will velocityName.

So here’s what our file looks like:

Workout Table Component

First, we need to import useState and useEffect, our Data object, and all of the Material-UI table components. We will also import a few more things from Material-UI: Paper to give our table an elevated effect, Container to surround the table, and Typography since we're feeling a little fancy today (it's to change the font of our titles.).

For the purposes of this app, our main lifts will only consist of two options: "Bench Press" and "Squat". These will flip flop based on whether "Upper Body" or "Lower Body" as been selected from the menu on app level. We will set this in state as MainLift. We'll also need the rest of our exercises and sets/reps to fill out the remainder of the chart, so we'll store that in state as well.

Notice how we’re also grabbing our props from the upper levels.

Let’s set up our functions that will change both of our state objects to their respective days.

Okay, so now we want to call one of these functions based on whichever day prop has been sent down each time a selection is made on that form. We will again use useEffect for this and set it's dependency array to consist of the day prop we're being passed. This way, any time day changes, the respective function will be called.

Now we need to set up a plan for how we will populate the “Target Velocity” column in the table, as well as how we will populate it’s respective name above the table (“Speed-Strength”, etc.).

This is a bit more complicated than it sounds. Not only do we need to grab the correct velocity object, but since the object being used needs to be one ahead of whatever has been selected in the dropdown menu (remember it’s populating their next phase), we’ll need to handle this all accordingly.

Let’s start by creating a function that grabs the current velocity object based on whichever velocityName prop was sent down and uses this to find what index it is located in in our Velocities array. This way, we can use that information to grab the next one ahead of it.

Now we’ll create two more functions to get the name (to populate the title) and range (to populate the velocity table cell) of whichever velocity object is one step ahead of the index we returned above. We also need to make sure that if the last object in the array is selected, we display the object at index 0. Otherwise, we’d be grabbing undefined.

Finally, we will create our table. We are going to need a conditional here. We only want the table to display once both dropdown menus have been selected. Until they’ve both been selected, we’ll display instructions.

Once the table is displaying, we’ll need to use our current exercises array which is set in state each time the day prop is changed to populate the exercises and sets/reps. Above that, we'll populate the main lift based on the day, and the velocity range based on our function above.

Here’s what this ends up looking like:

The final product:

Biggest Challenges

The biggest challenge for this app was the large amount of conditionals, resulting in a challenging way to write the code that was readable and understandable to others.

This was dealt with by creating very clear and concise function and variable names as well as descriptive comments for anything that may be confusing to read for an outsider. Functional programming was also used to combine any complicated statements/expressions into understandable chunks.

Future Goals

As mentioned at the beginning of this article, this app could have a lot more features added to it. These include:

  • Allowing the user to add their own exercises
  • A login/logout function that saves the user’s progress
  • Ability to record weights
  • More options for the types of days
  • Automatic integration from VBT software
  • Multi-day view
  • Display based on the type of program the athlete is on (amount of days/week, etc.)
  • and lots more…

Is there anything you would’ve done differently? Let me know in the comments!

PS: Here’s a link to the GitHub repo: https://github.com/ckaiser258/VBT-Planner

--

--