React/Redux Project: Creating a Gratitude Journaling Application

Kevin Peery
9 min readMay 21, 2019

After reading a book titled “Think Learn Succeed” by Dr. Caroline Leaf, I decided to make an app to help myself and others journal what we are thankful for in life in order to cultivate a mindset of gratitude to improve cognitive health. I learned that gratefulness quickly improves mental resiliency, increases longevity, promotes our ability to harness our imagination, and enhances our problem-solving aptitude. Problem-solving is integral to the software engineering field, so I knew that this app would improve my life by helping me keep a record of what I’m grateful for. This approach naturally encourages a gratitude mindset.

This is a React/Redux application so I won’t go into much detail about the Ruby on Rails backend, aside from pointing out the fact that it is completely separate from my React/Redux frontend. The code for the project can be found here: https://github.com/kevinptx/grateful

My styling is minimal for the purpose of saving time since the focus of this project is to understand the ins and outs of React and Redux. To start my project, I used the create-react-app generator.

Following React design principles, within the client side of the application, I created separate folders to house the actions, components, containers, and reducers. Other key files, all located in the root of the client under the src folder, are the App.js, store.js (the global state), and index.js files. Below is the conventional file structure for a React app with Redux for global state management.

In App.js, I have seven routes with react-router and proper RESTful routing practices. The Navbar remains present throughout as it is above the <Switch>. In order for routing to work, I imported:

{ BrowserRouter as Router, Route, Switch } from “react-router-dom”;

The files are broken down into Components and Containers.

How Redux Works in React

The purpose of Redux is to make the management of state more efficient. According to the Redux docs, “Redux has no relation to React. You can write Redux apps with React, Angular, Ember, jQuery, or vanilla JavaScript.” Redux is a library that can be used to compliment React by providing a way to easily store the data (global state or store) and the events (actions). Redux works especially well with the React library, because it allows you to describe UI as a function of state. Redux emits state updates in response to actions. The actions update the reducer, which in turn updates the global state (store). Redux isolates the state object from the components of the React app in order to avoid prop drilling, which creates super messy component props. Prop drilling is the cumbersome process of passing props to various components of the react app to get data to the various parts of the React component tree, adding more complexity to the entire app and creating more possibilities for bugs.

The diagrams above outline the flow of Redux. It can be summarized as follows:

  • The application’s state is held in a plain old JavaScript object (POJO) called the store. That global state (store) is updated by passing both an action and the old state to our reducer. The reducer then returns to us our new state.
  • To change our global state (store), (1) create an action, which is just a plain object with a type key. (2) Pass that action as an argument when calling the reducer, which is just a function with a switch/case statement. (3) The reducer then produces a new state. Actions are dispatched. The dispatch function persists changes to the store (global state). The dispatch function calls the reducer whose returned value is assigned to the new state. The only way to update a state is by dispatching an action: dispatch(action). The purpose of the type property of the action is to let Redux know about the event taking place.
  • The reducer must be a pure function which means that it has no side effects and that given the same arguments of state and action, it will always produce the same new state. Our reducer therefore never updates the previous state, but rather creates a new state object non-destructively, meaning it does not mutate the current state.

In my grateful app, we have an action to get all entries:

The Rules of Redux, stipulate the use of pure reducers, avoidance of mutations and side effects, and serializable state (no functions should be there). If you can’t JSON.stringify() it, then it is not serializable. Thunk middleware should be used to handle asynchronous actions, which could lead to side effects. For example, asynchronous actions making fetch requests to the backend Ruby on Rails API to update the global store is a good use case scenario for Thunk. Another use case for Thunk would be to set timers. This causes side effects and can lead to errors, which we want to avoid as a key Redux rule.

I placed my Thunk import in the redux store.js file. Notice also line 7 in the code snippet below for the additional reference to applying thunk middleware as well as the reference to rootReducer. According to the Redux docs,

The combineReducers helper function turns an object whose values are different reducing functions into a single reducing function you can pass to createStore.

The resulting reducer calls every child reducer, and gathers their results into a single state object. The state produced by combineReducers() namespaces the states of each reducer under their keys as passed to combineReducers()

Below is the src>store.js file:

See below the rootReducer in src>reducers>index.js

Below is my reducer for entries.js. Notice how when the above action of type: “GET_ENTRIES_SUCCESS” is called, that action.type is passed into the action argument of the reducer. The reducer is a simple pure function that takes in the current state of the application and an action to perform on the state as parameters. It then returns the updated state. They’re called reducers because their purpose is to take in a collection of values, reduce it to an updated state and then return it. The pure reducer functions, instead of mutating the original state, return the updated state in a new object using the non-destructive Object.assign({}) method and/or the spread operator (…). No mutations or no side effects are allowed in reducers. When we create a new state from the current state and an action, it gives us time travel because of transactional state transactions, which are loggable and reproducible. Transactional state transactions allow you to do everything in one block. Either the whole thing succeeds or the whole thing fails.

React Presentational Components

A component is part of the React API. A component is a class or function that describes part of a React user interface. In my grateful app, I use the EntryCard.js component to craft how each individual entry that is passed into the Entries.js container will look. I specifically call this component a presentational or a pure component since it does not contain state. This pure component simply takes in props and displays them, so this component is merely concerned with how things look. Notice also that, unlike my container components, this is not a class component. The predictability here, as a result of the functional programming principles of React, comes from the fact that this function will always return the same UI output if given the same props.

src>components>EntryCard.js:

React Container Components

A container is an informal term for a React component that is connected to a redux store. Containers receive Redux state updates and dispatch actions, and they typically don't render DOM elements. Instead, they are concerned with how things work and are therefore often stateful. Container components delegate rendering to presentational child components, like the EntryCard.js presentational component above, which handles the look of each individual entry. My Entries.js container component is rendering the entries by rendering the EntryCard.js presentational component with the props of entry and index. In my Entries.js container below, I imported {connect} from “react-redux” to have access to our store (global state). Now I am able to take that data and map it to the Entries.js container using mapStateToProps. This allows us to pass the entry and index props from Entries.js to our EntryCard.js presentational component.

By using mapDispatchToProps I can also take actions, and by wrapping them in a dispatch and an anonymous function, pass them as props to this Entries.js container. This removes all reference to our store from our container component. Instead of doing this by writing a mapDispatchToProps function, I took the shorter approach of directly passing { getEntries } as the second argument into the connect() function. In order to do that, I imported { getEntires } from my actions.

src>containers>Entries.js

React Components Summarized

  1. Functional components are often referred to as “presentational”, “dumb” or “stateless” components. They look like this: const cmp = () => { return <div>Some JSX goes here</div> }
  2. Class-based components are typically referred to as “containers”, “smart” or “stateful” components. They look like this: class Cmp extends Component { render () { return <div>Some JSX goes here</div> } }

I learned quite a lot about React and Redux through this project and am eager to continue applying my skills to create more apps.

https://github.com/kevinptx/grateful

Link to my GitHub repo for the grateful app: https://github.com/kevinptx/grateful

Sources:

--

--