Track Podcasts on Spotify w/ React/ Redux + Rails

Track Podcasts on Spotify w/ React/ Redux + Rails

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:

  1. Makes an AJAX fetch request (like GET or POST)
  2. Doesn't return anything until the fetched Promise object is resolved
  3. 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

Resources

Asynchronous Programming)

React Router

You Might Not Need Redux (Medium article by Dan Abramov)