Project Intro
For my fifth and final project at the Flatiron School, I decided to create a podcast tracker application that lets a user view, add and delete podcasts. Each podcasts has properties such as a name and a link to the podcast itself. The project is specifically titled "spotify-podcast-react-redux-project" on the repo because the seeded podcast data all contain Spotify links. I also intend on building off of this application in the near future by incorporating Spotify's new batch of podcast API endpoints.
Technologies Used
Like my previous project, the frontend and backend belong in their own separate repositories and are both housed under the main project repo .
Frontend
I was tasked with creating a React application that is connected to a Redux store. Despite it being a single-page application, I went with [react-router's] (reactrouter.com/core/guides/quick-start) <BrowserRouter />
, <Switch />
, and <Route />
components:
// ...frontend/src/App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
class App extends Component {
render() {
return (
<Router>
<div className="main-container">
<Switch>
<Route exact path="/" component={ Home } />
<Route exact path="/podcasts/new" component={ PodcastsNew } />
<Route exact path="/podcasts" component={ Podcasts } />
</Switch>
</div>
</Router>
)
}
}
Because the application state will be handled by a Redux store, I added a src/actions
and src/reducers
folder to house files whose job is to create actions and return an updated version of the state.
The actions I created were:
{type: "GET_PODCASTS", payload: podcast} //=> fetches the current state (the list of podcasts)
{type: "ADD_PODCAST", payload: podcast} //=> adds a podcast to the state ( becomes POST request to backend)
{type: "REMOVE_PODCAST", payload: podcast} //=> deletes a podcast from the database, removing it from the frontend (DELETE request)
Backend
As with some of my previous projects, I built the backend of the application in Rails (using the --api
flag to skip creating view files -- just the "MC" part of "MVC" ;) ).
# in the backend repo
rails new spotify-podcast-react-redux-project --api
For the most part, there isn't a lot of code that was written on this end. Most of the work was done in the podcasts_controller
, where requests from the frontend will go to be handled by the appropriate controller action.
class PodcastsController < ApplicationController
before_action :set_podcast, only: [:show, :update, :destroy]
def index
@podcasts = Podcast.all
render json: @podcasts
end
def show
render json: @podcast
end
def create
@new_podcast = Podcast.new(podcast_params)
if @new_podcast.save
render json: @new_podcast
else
render json: @new_podcast.errors
end
end
def destroy
@podcast.destroy
render json: @podcast
end
private
def set_podcast
@podcast = Podcast.find_by_id(params[:id])
end
def podcast_params
params.require(:podcast).permit(:name, :hosts, :genres, :link)
end
end
Challenges Faced
Understanding React-Redux State-Flow
As famously noted , Redux can often be more of a burden for developers than a blessing. This is especially true of smaller, simpler applications and especially ones that are already fetching data from a backend API.
Despite how superfluous this may seem, the point of this project was for me to demonstrate my knowledge of React-Redux state-flow (just with Rails thrown in the mix!).
Essentially, react-redux state-flow is unidirectional in nature; the parent React component passes down it's store-accessed information to it's child components as props. Those children can then work with those props to render data in interesting ways. The "redux" part of the state-data flow is essentially this: Action ==> Reducer ==> New State.
Regardless of what technology Redux is paired with (even React), it always follows this flow. Actions are dispatched to the Redux store, where a shallow copy of the old state and an updated version of the state are merged or reduced, which then returns the new state (and thereby updating the store).
Asynchronous Programming w/ Redux Thunk
Another challenge for me was understanding the inner workings of Redux Thunk.
One of those unavoidable parts of programming is asynchrony).
In the context of a React-Redux application, in the src/actions/index.js
file, it isn't enough to simply return an object with the action information (type
and payload
). Instead, thank in large part to the Thunk middleware, we can return a callback function that:
- Makes an AJAX fetch request (like
GET
orPOST
) - Doesn't return anything until the fetched Promise object is resolved
- Returns a dispatched action with the action object passed in
Even after this project, I'm still not feeling too confident with async programming. However, I definitely feel good about ultimately getting it to work in this project.
If you'd like to check out the project for yourself, clone the repo and enjoy!
Happy Coding, Brandon