Creating my React-Redux Portfolio Project

William Pannell
5 min readAug 6, 2021

While learning to skateboard, it soon becomes apparent how many tricks are out there you are able to learn as well as how long it takes to truly master a single one. For my final project, I decided to build an application that allows users to track the tricks they have learned and rate their proficiency with each trick in order to help record an individual’s skateboarding progress.

I started setting up a backend first since I already had an idea of what the data’s relationships would be. I made a many-to-many relationship between a user and a trick, accomplished with a has_many (users, tricks) :through => :user_tricks. The purpose of user_tricks and this relationship was to allow each user to have their own set of logged tricks where multiple users could log the same trick. This would also allow me to access the data of which user has logged which trick easily. User_trick also had an attribute of proficiency, allow each trick a user has logged to have its own unique proficiency rating to go with it. I would then create the migration files and seed the database with 20 different tricks they could create associations with.

By using rails generate, I was also able to create controllers and routes for each model quickly. Although I would have to return and modify some parts, this allowed me to later access database information with Axios. Also, I created serializers for each model in order to return that information as JSON in order for that data to be used with the front-end side.

After getting react set up and rendering upon running rails s, I began working on the components. Using react-router-dom, I was able to set up a home screen with links to empty components for logging/signing in, viewing the user's trick log, and the list of all possible tricks available to log.

Before filling in these components, I set up a backend with redux and redux-thunk in order to store and track state. I created a folder for each User, Trick, and UserTrick model containing a file for the respective reducer, type, and action as well as files for the store and rootReducer. The store file used createStore with the rootReducer, and rootReducer would use combineReducers with the reducers for each model.

Each model’s type file was made for easy clarification of which action should be performed. Using redux-thunk I was able to make async actions that would utilize Axios, and based on the actionType, call the api to receive/update information on the appropriate model’s database info and return that as a payload. The payload was then used with the reducer in order to update the state of each model. Though more tweaking would be done, this initial setup would allow me to access state easily within each component.

The component for the list of tricks was the first to be filled out. When called, this component would dispatch the fetchTricks action in order to store all of the seeded tricks into the state. It returns another component that would access this state with useSelector and return a card made from mapping the array of trick objects’ information. In addition, each card would have a link to a show page for each individual trick that would display additional information of how many users have logged the trick and a button to log that selected trick to the current user’s log. That button would call an action that would create a new UserTrick with the id of the selected trick and the id of the current user if it didn’t already exist.

Next up was creating the sign-up portion for the user. A form was made to enter a username. When submitted, it would create a new user if the name didn’t already exist and log them in, or login the user if the name was present in the database- accomplished by another action call. Then the now logged-in user would be stored in the currentUser state and displayed on the home view.

With access to both the user and seeded tricks in the state, as well as the ability to update and retrieve that information, it was time to create the last and most important component- the log. In order to print out the correct tricks, I was able to actually use the useSelector with the user and then specify that I wanted all of their tricks’ attributes. This was due to putting in the relationships within the serialized JSON file. A separate component took this as props and would display each one as a card similar to the flow of the “list of all trick” part. Updating the proficiency with each user trick was more cumbersome though. I had to access the id of each UserTrick associated with the current user by accessing the UserTrick state by iterating through all of the UserTricks created between all users and checking if they had a user_id equal to the current user. This was important as I would need this id in order to update the correct UserTrick proficiency attribute with a UserTrick action. I implemented a slider for each trick in order to change the proficiency, and once submitted, would take that UserTrick id I got earlier, the current user’s id, the trick id, and the slider value, call the UserTrick action with those parameters, and then find and update the right UserTrick’s proficiency within the database. Following creating that I would also add a button to remove a UserTrick that would send a call to delete the UserTrick from the database.

With all of that working, I would then style the components with styled-components, as well as make a check to ensure you can’t enter the log component if no one is logged in.

At first, I was somewhat overwhelmed with all of the responsibilities required for this project. Though after setting up a good foundation, I found that it became much easier to think about what to do next. Having the ability to view the state of data is incredibly helpful. I would constantly check the Redux DevTools in order to make sure the right actions were called, the state was updated correctly, check the state tree for information, and so on. Also, creating components that are designated to specific functions of the overall application makes it much easier to navigate through code and helps ensure a separation of concerns. I learned a ton from this project and look forward to working on more.

--

--