Sunday, May 17, 2020

Final Boot Camp Project ... now with React/Redux!

And so, five months after I officially started this journey, I've come to my final project for Flatiron School's Online Software Engineering program. When I think back to our first project -- a text-based game written in Ruby that runs through the command line -- it strikes me that the "programming" itself has not gotten any more complex. Programming structures (conditionals, loops, variables, etc.) are programming structures regardless of the language or the complexity of the project. The real difference between my final project and my first project is the technologies used to create it. 

For my final project, I continued on my quest to create the perfect recipe management app (basically, an app that I wish I had for managing my own recipes!). For the back end, I built a custom JSON-serving Rails API (similar to the last project). I created the front end using JavaScript and the ReactJS libary, along with Redux for state management and Redux-Thunk middleware to handle asynchronous fetch requests to the back end. I also utilized the React Bootstrap library to make my styling a breeze!

Some New Tools: React and Redux


I must admit that I was not excited about starting React. I am someone who really likes to understand exactly what is happening at each moment my code is executing, and so "vanilla JS" really appealed to me. Call me crazy, but I really liked manually updating the DOM to reflect exactly the changes I wanted to see. While other folks seemed mesmerized by "React-magic", I felt a little uncomfortable with not having hard-coded all of the DOM changes myself. 

As I started to work more with React, though, I started to see the beauty of having my code organized into components. It gave structure and order to my JavaScript code where coding in JS had previously felt a bit like the wild west. In React, the App class is essentially the parent component that's in charge of all the visible content of the app. The building blocks of the React application are components, which are chunks of code that let you split the user interface into independent pieces. A particular component can then be rendered by its parent component, which can also pass down information to that child component (kind of like parameters when calling a function) in the form of props. A point that was emphasized over and over is that changes in props can only happen externally; i.e., if the parent component "remakes itself" and then re-renders the child component. A component gets re-rendered to the page whenever there is a change to its state or props.

Of course, as soon as I started feeling comfortable with React, Redux came into the mix! It was a little tricky to wrap my head around Redux at first, but like anything you just need to "feel out the contours and wait for your eyes to adjust" (an approximate quote from one of Flatiron's founders, and one that I have on a sticky note next to my computer!). Redux is a "state-management tool" that places all of our application's data in a single state ("the store"), which is just a plain JS object. To change our state, we need to create an action that holds information for how to update the state. Reducer functions take in a previous state and an action and return an updated state that results from applying the action to the previous state.

How does our React app connect to the Redux store? With a connect function that itself calls a particular function (usually mapStateToProps and mapDispatchToProps) whenever there is a change in the state. Whatever that function returns will get passed down to the "connected" component as props.

The purpose of Redux is to maintain a single source of truth for your application on the front end, as opposed to having different data structures in all of your JS classes that keep track of various information. While I was able to see this to a small degree in my own project, I imagine that a larger-scale project would really benefit from such predictable state management.

My Recipe Box


So, how did I incorporate these tools into my final project? My Recipe Box allows the user to create recipe cards with their favorite recipes from around the web, categorize the recipes for easy access, record any notes they'd like to remember for the next time they make the recipe, and see all their friends' recipes as well!

My main presentational component is RecipesContainer, which is responsible for displaying a set of recipe cards by rendering the RecipeCards component. RecipeCards, in turn, does some filtering of the recipes and then for each recipe, renders a recipe card. Finally, the RecipeCard component is responsible for displaying an actual recipe card, along with the user's notes about the recipe, a link to the recipe on the web, and a button for adding a recipe note. Of course, there are other components as well: a NavBar for navigation, a RecipeForm for adding a new recipe to your box, etc. Not to mention components related to user authentication, which was a challenge I had been avoiding but I'm glad I finally tackled!

Where does Redux come into play? When my front end sends an API request to, say, load all of the recipes from the database, those recipes get stored in the Redux store (i.e., the global state). The store keeps track of other information as well: all of the users, all of the recipe notes, the current user, whose recipes you are currently viewing, which category of recipes you are currently viewing, etc.

There were definitely some decisions involved in terms of which React components to connect to the Redux store, and I'm sure this is something that will change as I go back and refactor my code. For now, I chose to map most of my state and dispatch functions to props in my parent App component and then only connect to the store for more specific needs further down the chain. For example, RecipeCard connects to the store to grab all of the notes and the function for adding a new note (triggered by an "add note" button on a recipe card).

Overall, I learned a TON through this project and am excited to continue refining it so that I can release it to the world (or at least a small circle of friends)! Feel free to check out my repo here, and thank you again for continuing to join me on this journey!