For my final project, I built a video tutorial note taking application, implementing a React-Redux frontend UI with a Rails API backend. A user signs in using Google and can then search the Youtube API for video tutorials. Upon finding and selecting a tutorial the user can then take notes during the tutorial which are persisted to the Rails backend data base when a note is created, and can be retrieved, edited or deleted.
I used Google-Auth for user sign in and Axios which handled the network (http) requests to the Youtube API for video searches. Both were my first challenges to implement and required watching a couple video tutorials (without a working note taking app yet) and a lot of trial and error.
React-Redux frontend:
React, which is a JavaScript library used to build front end user interfaces, is comprised of small re-usable components which use a render()
method to return what is displayed. Data can be passed to components in props and accessed by render()
through this.props
. In Addition to passing data to react components, components can maintain their own internal state data which can be accessed in render()
with this.state
. In React, every time state is updated the view is re-rendered and this is important to remember later, when I talk about the bug which was the bane of my existence for days. React was a lot of fun to work with because with a little work it becomes easy to understand. The idea of breaking the frontend down into reusable pieces of code (components) makes sense in terms of single responsibility, abstraction and is just very clean. This was fairly easy to understand and work with, and it is a lot of fun when you’re tracking right?
Things become a bit more complex when using Redux to manage state. React is fun, but in larger applications, state can become difficult to manage. Enter Redux, which is a library that allows your application to have global application state that connected components can access, rather than multiple components with internal state which can become confusing. Redux manages application state with a global object called Store, which is a central repository of application data and cannot be changed directly. It is how state is updated that adds another layer of complexity in that we need action creators, dispatch, and reducers. An action creator creates an action which is a JavaScript object that represents some change to our data. This action object has an action type which describes the change and a payload property which describes the context of that change. Dispatch (a function of redux store) copies the action object and sends the object and existing data to a reducer (pure function) which processes the action and existing data updating and returning updated state to the Store.
So, back to my note taking application which I called Copious. Like I said, a user signs in with Google and can search the Youtube API which is handled by Axios making asynchronous network (http) requests in my action creators. When a video is selected, the user can make notes on the tutorial and the notes are persisted/created, read/retrieved, updated and deleted through asynchronous fetch requests to the Rails backend. My Copious app uses React Router for client-side routing, which allows single page app navigation without page refreshes, using the React structure to call components that render/display the information.
I tried to avoid using redux forms for the actual note content, because redux forms adds another layer of complexity. But… I had problems connecting my regular forms to the redux store and in the end, that’s what redux forms does well, so I was forced to acquiesce, which gave birth to the bane of my existence bug that I mentioned earlier.
Very near completion, my app was working and application state (videos, selected video, notes, and selected note) was updating. Notes were being persisted to the data base, the links in a user’s tutorial/notes list were working to return user to the tutorial except…
the note content would not render. The note content existed in the database on the backend, and it existed in state on the frontend, but the content would NOT render with the tutorial and I just could not figure out why!
Here’s the deal. If you ever use redux forms in this circumstance, remember… when the form data is used to update state in redux store – “In react when state is updated the view is re-rendered”. Upon re-render redux form deletes the initial values and the form is rendered without the data, and I wanted that data. In redux store, note content exists, but the form is re-rendered without the initial values, this is what redux form does when component unmounts.
This became the bane of my existence or my apps existence, depending on how you want to look at it. I needed to render note contents in an edit form, so the user could make edits to the notes.
In the end, and after much googling, I found a Stack Overflow question that I almost dismissed, but it provided a work around that was very simple and with one quick expression the bane of my existence bug was put to death.
destroyOnUnmount: false
export default reduxForm({ form: 'NoteForm', validate: validate, enableReinitialize: true, destroyOnUnmount: false })(NoteForm)
Copious works and although challenging, it was fun to build. The most fun is watching that note content render. I can’t decide which was more arduous, building the app or writing this blog post. No matter the challenges of the application, it was much more fun. So the blog post wins out as the most arduous part of this project.