Tablet showing the Maintainers Anonymous podcast on the Podcasts app.

I created this Podcasts web app as an excuse to build something with React. And a single-page app architecture makes sense for a podcast app, to allow media to play as you browse.

Very nicely done.

– Dan Abramov, React core team via twitter

Managing the app state with reducers

The app uses React Router v6 for navigation, which has a new React Hooks-based API which is really nice to work with. I used React’s in-built reducers (useReducer) along with the Context API to manage the app state. React’s reducers work similarly to Redux, but are guaranteed to have forward compatibility with the upcoming Suspense API and Concurrent Mode. Dan Abramov’s two egghead.io courses on Redux are an excellent resource for learning how reducers work.

Tablet showing the home page of the Podcasts app.

Parsing RSS feeds with Netlify functions

For the backend I used Netlify functions, which run on AWS lambda. This allows the app to read RSS feeds without running into cross-origin issues. To improve performance, I used an RSS parser that supports streams. This allows me the first 30 episodes from the RSS feed without downloading the whole feed, making feeds load in seconds – even for feeds over 5MB in size, such as Javascript Jabber.

Tablet showing the business category page of the Podcasts app.

Syncing the audio element with the app state

One of the trickiest parts was working around the “impedance mismatch” between the React programming model and the browser’s native audio element. I initially wanted to have the audio element be driven by the app state, however, the element can also be controlled by the browser. Media playback can be controlled with function keys on keyboards or though phone lock screens and notifications. A better approach turned out to be to let the audio element take care of its own state, and use event listeners to keep the app state up to date. To do this, I had to be able to call the play() and pause() methods on the audio element from anywhere in the app. I made the audio element available globally using useRef with the Context API.



iPad Pro showing the interactive "The Journey" graphic.