Redux From Scratch (Chapter 3 | Implementing With React)

Michael Mangialardi
Coding Artist
Published in
23 min readJul 4, 2017

Buy the Official Ebook

If you would like to support the author and receive a PDF, EPUB, and/or MOBI copy of the book, please purchase the official ebook.

Prerequisites

Chapter 1 | Core Concepts
Chapter 2 | Practicing the Basics

Scope of This Chapter

In the previous chapter, we dipped into the basics of Redux. We used Codepen to keep the build “behind the scenes” and we wrote our code in vanilla JavaScript.

In this chapter, we will start by creating our own React & Redux project for local development. Then, we will implement our first React & Redux app. This app will a step up from the difficulty of our previous apps. We won’t be loading any data from an API or database until later in this book. However, we will be getting a practice with create, read, update, and delete operations with Redux.

We have a lot to do, so let’s get started!

Creating a React & Redux Project

Initial Setup

Let’s start by creating a folder for our project called BookCards.

cd into BookCards from command line, run npm init , and hit enter through all the prompts.

Open the BookCards project folder in a code editor of choice (I am using Atom).

Install Dependencies

Let’s install react and react-dom:

npm install --save react
npm install --save react-dom

Then, we need to install the core Redux library:

npm install --save redux

We also need to install another library when using Redux with React:

npm install --save react-redux

For this project, these will be all of our dependencies. Our package.json file should currently look like this:

{
"name": "bookcards",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-redux": "^5.0.5",
"redux": "^3.7.1"
}
}

Installing devDependencies

For our devDependencies, we need to install Babel stuff to use ES6 features in React, Webpack to apply the Babel preprocessing, and Webpack Dev Server to host our application.

Here’s all of it in one installation:

npm install --save-dev babel-loader babel-core babel-preset-env babel-preset-react webpack webpack-dev-server html-webpack-plugin

If you aren’t familiar with why we are doing all of this, here’s a helpful chapter from another book I’ve written.

Our package.json now looks like this:

{
"name": "bookcards",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-redux": "^5.0.5",
"redux": "^3.7.1"
},
"devDependencies": {
"babel-core": "^6.25.0",
"babel-loader": "^7.1.1",
"babel-preset-env": "^1.5.2",
"babel-preset-react": "^6.24.1",
"html-webpack-plugin": "^2.29.0",
"webpack": "^3.0.0",
"webpack-dev-server": "^2.5.0"
}
}

Setting Up Project Directory

First, let’s add a file under the root of our project called index.html and add the following code:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Book Cards | React and Redux</title>
<link rel="stylesheet" href="styles/main.css">
</head>
<body>
<div id="app">
</div>
</body>
</html>

Nothing special here. We just have<div id="app"></div> to inject our React application and a link to a CSS file.

Let’s create a folder called styles from the root of our project. Let’s also create a file called main.css within this folder. Add the following to this file:

@import url('https://fonts.googleapis.com/css?family=Lato:400,700');h1,h2,h3,h4,h5,h6,p {
font-family: "Lato"
}

We also need to create a file called index.js. This will be the top level of our React application that will get bundled by Webpack and injected into index.html.

This is all standard setup. However, we now have to set up our project directory in ways specific to a React & Redux project.

We will have two separate folders in the root of our project for our actions and reducers. These folders will just contain Redux code and no React components.

We then need to create two separate folders for our React components.

If you recall, I distinguished between two types of React components that we will have when using Redux: active and static.

The static components only are concerned with rendering something with inherited props.

The active components are actively getting data from the store to pass down to the static components. In other words, the active components provide props to the static components (hence why I also called the provider components).

I made a note that the official terminology for this distinction is container (active/providers) vs. presentational (static) components. While I prefer the active/provider and static terminology for teaching the concepts to a beginner, the official terminology makes sense once you see the React code.

All of that to say, let’s create a folder called components within the root of our project. Within components, let’s create two folders called containers and presentationals.

Our project directory should look like this at this point:

Configuring Webpack

Add a file to the root of our project called webpack.config.js and paste the following code:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html',
inject: 'body'
})
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react']
}
}
}
]
},
plugins: [HtmlWebpackPluginConfig]
}

In the code above, we are going to take our index.js which is the entry level of our React application, apply the Babel preprocessing for ES6 and React code to make it work in browsers, and output a bundled file called bundle.js.

Bundle.js will be injected into index.html via the html-webpack-plugin as defined here:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html',
inject: 'body'
})

The final step is to create a script that will launch our app using webpack-dev-server.

Update the scripts in package.json to the following:

"scripts": {
"start": "webpack-dev-server"
},

Testing Our Project Setup

Let’s make sure we set this up correctly.

Update index.js to the following:

import React from 'react';
import ReactDOM from 'react-dom';
class App extends React.Component {
render() {
return (
<div>
<h1>Hello React & Reduct Project</h1>
</div>
)
}
}
ReactDOM.render(
<App/>,
document.getElementById('app')
)

Then, run npm start from command line and check the local host:

Woohoo! With this aside, it’s time to write some React & Redux code!

Breaking Down the App

Really quickly, let’s discuss what app we will make for our first Redux & React application.

We are going to make an app that allows you to create, read, update, and delete a book (CRUD).

This will not only give us practice with implementing React and Redux, but also the common operations that we would do with Redux.

Specifically, our implementation will look like this:

To start, we will have a store, reducers, and actions using Redux. The state within the store will have information about a book that we manually define. The store will be made accessible to our React components. The Books component will be a container component. Therefore, it will actively read the properties from the store’s state, nest the Book Card component, and pass the properties down. The Book Card component will then render (or present) a book to the DOM as it will be a presentational component:

Once we get this working, we will update our reducer, add actions to be able to create, update, and delete a book from the state, and tweak our rendering via React as needed.

Let’s begin!

Writing Our Initial Redux Code

So far, we have set up our first React and Redux project. Given the way our project directory is set up, we can divide our code into different folders for a modular approach.

Let’s follow the same flow as we did in the last chapter when it comes to writing our Redux code. This time, we will just place everything in its proper folders and files. For this section, however, we don’t have as much code to write as we just want to manually specify some data in our state that our React code can ultimately render as a book card component.

The first thing to do is create a reducer file called BooksApp.js within the reducers folder. We want to begin by defining the initial state:

//define the initial state
const initialState = {
cover: "https://s3.amazonaws.com/titlepages.leanpub.com/reactjsforthevisuallearner/hero?1496374274",
title: "React.js for the Visual Learner",
author: "Mike Mangialardi",
link: "https://leanpub.com/reactjsforthevisuallearner"
}

For now, we are manually specifying a cover image address, title, author name, and link address.

Next, we initialize the state and return it like so:

//define a reducer with an initialized state action
function BooksApp(state = initialState, action) {
//eventually adding logic to handle create, update, and delete
return state
}

The final piece is to make our reducer exportable:

export default BooksApp

Since we have no actions at the moment, we can move on to index.js.

As far as Redux code, we start by importing createStore from the Redux library:

import { createStore } from 'redux';

We also have to import the reducer we just created to pass in as a parameter to createStore() :

import BooksApp from './reducers/BooksApp';

Then, we can initialize the store between the App component class and the React.DOM.render(..) like so:

//initialize store
let store = createStore(BooksApp)
console.log(store.getState());

I also added a log so we can make sure this is working.

If we go to the local host and refresh, we should see the following in the console:

Neat! This completes the initial Redux code.

Writing Our Initial React Code

The first thing to do is to finish off our index.js file.

First, let’s import our container component called Books which we will create in just a bit:

import Books from './components/containers/Books';

Then, let’s nest this component into our App component like so:

//top level of React component hierarchy
class App extends React.Component {
render() {
return (
<div>
<Books />
</div>
)
}
}

We want to pass down the store to our Books component. So, how do we do that?

We have to use a predefined component called Provider from the react-redux library.

Let’s start by importing it:

import { Provider } from 'react-redux';

Then, we just have it around our App component that is being rendered via ReactDOM:

ReactDOM.render(
<Provider>
<App/>
</Provider>,
document.getElementById('app')
)

After that, we can pass in the store as a prop like so:

ReactDOM.render(
<Provider store = { store }>
<App/>
</Provider>,
document.getElementById('app')
)

Now, all of our container components can pass down the store as a prop. Let’s do this for our Books component:

<Books store={store} />

We are now complete with the index.js file.

Let’s create a new file called Books.js within the containers folder. We have already nested and passed down the store as a prop to this component.

First, we can write the standard React code that will import React, import the Book Card component (presentational component that we will create shortly), nest the Book Card component in the Books class, and make the Books component exportable:

import React from 'react';import BookCard from  '../presentationals/BookCard';//Provider/Container React Component
class Books extends React.Component {
render() {
return (
<div>
<BookCard/>
</div>
)
}
}
export default Books

Nothing surprising here.

Now, we need to do special stuff for Redux. Recall, the Books component has access to the store component as an inherited prop.

In vanilla JavaScript, we could get the state of a store like so:

store.getState();

Therefore, we can read the current state via getState() and store the result into a variable just like this:

render() {
const stateProps = this.props.store.getState();
console.log(stateProps);
return (
<div>
<BookCard/>
</div>
)
}

We can then pass down stateProps as a prop to BookCard:

<BookCard stateProps = { stateProps }/>

Before we move on, we have to import getState from the Redux library in order for it to work:

import { getState } from 'redux';

Cool! Let’s move along to our final initial React code, the Book Card component.

Create a new file called BookCard.js under the presentationals folder.

In this file, we only have to worry about importing the React library:

import React from 'react';

Then, we just create a component BookCard, render the elements we want to present using the inherited stateProps object properties as needed, and make the component exportable:

//Provider/Container React Component
class BookCard extends React.Component {
render() {
return (
<div>
<img style={{width: 250, height: 323}} src={this.props.stateProps.cover} />
<h2>{this.props.stateProps.title}</h2>
<h3>{this.props.stateProps.author}</h3>
<a href={this.props.stateProps.link}>{this.props.stateProps.link}</a>
</div>
)
}
}
export default BookCard

We have now written all the initial Redux and React code to define a state within a store, perform a read of our state, and use the data to ultimately render a book UI card.

Let’s check the local host and see if this is working:

Cool beans!

If you look at the console, you can see the store initialized in index.js and the store that was read in Books.js being logged:

Look great!

Implementing Flexbox in React

In the next section, I want to focus on being able to add, edit, and delete book card components like we have just made. This means that we need the functionality to render multiple book card components and maintain good styling.

To do this, we will be using a Flexbox layout implementation.

If you already know Flexbox or would rather learn it at a different time, you can grab the updated code from this section and move on.

If you don’t know Flexbox, I really encourage you to pay careful attention to this section as it is a very important skill to have as a web developer.

Grid System

Creating any user interface requires organization of the layout. One option is to use a grid system, like react-grid-system. The idea is to organize the user interface into rows and columns.

For example, let’s say we want to display the following section:

In terms of rows and columns, this section would be 1 row and 2 columns:

Each section of a user interface with React would need to be defined in terms of rows and columns.

With a grid system, you have to define the width of each column.

For instance, Bootstrap’s grid system allows you to define the width of columns in a way that gives you all of the following options for a row:

A Flexbox implementation provides a more flexible alternative. Let’s look into the basics.

Flexbox Basics

Let’s explain these basics concepts behind Flexbox using some nice visual aids.

With Flexbox, we start off with a container with a specified width:

Then, we would specify the direction of our container (if we want the container to be a row or column).

Here’s an example of a row direction:

Here’s an example of a column direction:

Let’s say we specified a row, Flexbox invisibly draws a horizontal main axis line like so:

As we add items in our container, the items will be added in the direction of this main axis. In the case of a row, items are added horizontally. In the case of a column, items are added vertically.

Continuing with our row example, let’s add 3 items:

By default, Flexbox will fit all the items in one line of the container. Therefore, if we wanted to add another box to our container shown above, all the boxes would shrink so they all fit:

When the main axis is drawn by Flexbox, there is a cross axis that runs perpendicular to the main axis:

If we specified a column direction, the main axis would be running vertically and the cross axis would be running horizontally.

Putting it all together, here’s the final visualization of our row:

Now that we understand the setup of the main axis and cross axis, there are a few different ways to control the alignment of our items in relation to the axes.

The property to align our items is align-items.

align-items refers to how items will be laid out across the cross axis.

There are 4 possible properties of align-items in Flexbox:

stretch, flex-start, center or flex-end

stretch means that the items will stretch to fill the container along the cross axis.

For example, items within a column container would stretch like this:

Note the height of this item would be specified manually. Also, stretch is the default value in Flexbox.

flex-start means that items would be laid out at the start of the cross axis. This will be the very left point for a column and the very top point for a row.

Let’s say we had specified a manual width for an item that was 50% of a column container. The item could be laid out like this:

flex-end would lay out the items at the end of the cross axis:

center will have items centered on the cross axis:

How an item is laid out across the main axis is specified by the property called justify-content.

We can have 5possible values: flex-start, space-around , space-between , center , or flex-end .

flex-start, flex-end, and center work the same as in align-items except in relation to the main axis.

space-between means that the items would be justified evenly across the main axis with the first item on the start and the last item on the end:

space-around means that the items would be justified evenly across the main axis and equal space around the start and end:

This concludes the basic concepts of Flexbox. As a reference, I recommend this guide.

Let’s go ahead and implement a Flexbox container in our project.

Implementing Flexbox

In Books.js, let’s add a class called books-container to the outermost div:

<div className="books-container">
<BookCard stateProps = { stateProps }/>
</div>

Let’s also nest a second BookCard component for testing:

<div className="books-container">
<BookCard stateProps = { stateProps }/>
<BookCard stateProps = { stateProps }/>
</div>

Open BookCard.js and let’s add a class called book-card to the outermost div:

<div className="book-card">//stuff here</div>

Finally, we can go to main.css to add our styling.

First, we add the styling for our books-container class which will be the Flexbox container:

.books-container {
display: flex;
flex-direction: "row";
-webkit-align-items: center;
align-items: center;
-webkit-justify-content: center;
justify-content: center;
height: 100vh;
}

We are going to have our book card components going in a row direction and being centered across the main and cross axes.

Then, we add the styling for the items within this Flexbox container like so:

.book-card {
position: relative;
margin: 20px;
}

Save your files and check the local host. We should now see the following:

Cool beans!

Completing All CRUD Operations

So far, we just read from the initial state defined in our Redux code and used the data to render UI elements via React.

Let’s turn it up a notch and get extra practice performing creating, updating, and deleting operations through dispatched actions.

Adding Icons

We can start by adding icons to our BookCard component that will dispatch actions on a click event.

First, let’s add FontAwesome icons by opening index.html and adding the following in the head:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">

Next, let’s add the icons in BookCard.js like so:

render() {
return (
<div className="book-card">
<img
style={{width: 250, height: 323}}
src={this.props.stateProps.cover}
/>
<h2>{this.props.stateProps.title}</h2>
<h3>{this.props.stateProps.author}</h3>
<a href={this.props.stateProps.link}>
{this.props.stateProps.link}
</a>
<br/>
<i className="icon fa fa-pencil" aria-hidden="true"></i>
<i className="icon fa fa-trash" aria-hidden="true"></i>
<i className="icon fa fa-plus" aria-hidden="true"></i>
</div>
)
}

Finally, let’s add the following styling to main.css:

.icon {
position: relative;
margin-top: 10px;
margin-right: 10px;
}

Save and check the local host.

From left to right, we now have an icon to edit (update), delete, or add a book card component:

Right on!

Implementing Add and Delete Operations

In the next two chapters, we will be working with an API and Firebase so that we can dynamically load information about books.

In this chapter, we are just going to practice adding and deleting the same book component (that has information which we manually defined).

In our Books.js file, we manually nested two BookCard components:

class Books extends React.Component {
render() {
const stateProps = this.props.store.getState();
console.log(stateProps);
return (
<div className="books-container">
<BookCard stateProps = { stateProps }/>
<BookCard stateProps = { stateProps }/>
</div>
)
}
}

We want to add to a numbers in an array for how many books to render in our initial state. Then, we want to render BookCard components to match this number. To control the adding and deleting of our BookCard components, we just have to pop or push from that array.

For example, if we had an array like this our state: books: [0,1,2], then we will render 3 book cards. If we popped a number off the array, then we will render 2 book cards and the array will look like this: books: [0,1].

We will dispatch an action on the plus and trash icons to update the array accordingly which will cause an effect of adding or deleting book card components from being rendered.

To implement this, let’s being by opening the reducer in BooksApp.js.

Let’s add the books array to the state:

//define the initial state
const initialState = {
books: [0,1],
cover: "https://s3.amazonaws.com/titlepages.leanpub.com/reactjsforthevisuallearner/hero?1496374274",
title: "React.js for the Visual Learner",
author: "Mike Mangialardi",
link: "https://leanpub.com/reactjsforthevisuallearner"
}

Because we have 2 numbers in our array, we want to render 2 books. Each number will be the key (id) of the book card.

Now, open Books.js.

Just above the return, we create a new array called bookItems that will store the <BookCard stateProps = { stateProps } /> components which we want to nest in our return:

const bookItems = stateProps.books.map((book) =>
<BookCard stateProps = { stateProps } />
);

This can be read as: “For each book in the books array found in the state, please add the <BookCard stateProps = { stateProps } /> component to our new array being stored in bookItems variable.”

Then, we can inject the bookItems array into our return and React will automatically render each component in this array:

return (
<div className="books-container">
{bookItems}
</div>
)

Let’s test this out.

We are getting an error which tells us that we need to specify a key prop for each BookCard component.

Replace the existing code with the following:

const bookItems = stateProps.books.map((book) => {
console.log(book);
});

We can now see what book is when we go to the local host and check the console:

book is the number in the books array for the current iteration. We can use this value for the key prop we need like so:

const bookItems = stateProps.books.map((book) =>
<BookCard key = { book } stateProps = { stateProps } />
);

Now, we everything should be working:

Just to be safe, we can manually update the books array found in the initial state of our reducer in BooksApp.js like so:

books: [0,1,2,3],

Now, we can see the following in the local host:

Woah!

The next step is to control the books array in our state via dispatched actions on the click of the plus or trash icon for each book card component.

Before we do this, let’s make sure we understand how we can pop and push from an array in a state depending on the incoming dispatched actions.

I created a demo on Codepen which you can view here (it’s just a tweak of our counter app):

In this pen, we start with an initial state that is just an empty array.

When an INCREMENT action is being dispatched, we create a copy of the current state and push a new value. To push values in numeric order, we always just push the length of the current state. Then, we return the new state.

When a DECREMENT action is being dispatched, we create a copy of the current state, pop off the end value, and return the new state.

This is the exact functionality that we need to implement. However, our array in the state is within a JavaScript object so we need to tweak this logic slightly.

I also made a demo to test this out before we do it together. You can view it here:

As you can see, we have a numbers property within the initialState object which is an array.

When an INCREMENT action is being dispatched, we create a copy of the current state object and push a new value to the numbers array. Again, we always just push the length of the current array. Then, we return the new state object.

When a DECREMENT action is being dispatched, we create a copy of the current state object and pop a new value to the numbers array. Then, we return the new state object.

This results in the same functionality:

Perfect!

Note: I also made a sweet tweak to have proper rendering in this demo:

//render value of state to DOM
let countTarget = document.getElementById('count')
function render() {
const stateCopy = store.getState()
countTarget.innerHTML = stateCopy.numbers
}

Alright, we are now ready to update the reducer in our own project.

Go to BooksApp.js and let’s update our reducer:

//define a reducer with an initialized state and logic to handle action
function BooksApp(state = initialState, action) {
switch(action.type) {
case 'ADD_BOOK':
let incremented = Object.assign({}, state)
incremented.books.push(incremented.books.length)
return incremented
case 'DELETE_BOOK':
let decremented = Object.assign({}, state)
decremented.books.pop()
return decremented
default:
return state
}
}

This is very similar to the demo except our array is a property called books. Also, the action types are going to be ADD_BOOK and DELETE_BOOK .

Let’s add those action creators now.

Create a new file in the actions folder called DeleteBook.js.

Just like our demo, our action just needs to contain the type:

//define action within an action creator
function DeleteBook() {
const DELETE_BOOK = 'DELETE_BOOK'
return {
type: DELETE_BOOK
}
}
export default DeleteBook

Create another file in the actions folder called AddBook.js and add the following:

//define action within an action creator
function AddBook() {
const ADD_BOOK = 'ADD_BOOK'
return {
type: ADD_BOOK
}
}
export default AddBook

The final piece is to dispatch these actions on the click of correct icon.

Open Books.js.

Because this is our container (active) component, it will have the event handler for the onClick events which will dispatch the actions. The event handler will be passed down to our presentational component in BookCard.js.

First, we import both our action creators:

import AddBook from '../../actions/AddBook';
import DeleteBook from '../../actions/DeleteBook';

Then, we add an event handler called dispatchAction :

dispatchAction (input) {
switch (input) {
case "TRASH":
this.props.store.dispatch(DeleteBook());
break;
case "PLUS":
this.props.store.dispatch(AddBook());
break;
}
}

This event handler will be passed an input that will indicate which icon is calling it. Depending on the input, we can dispatch the proper action using the following syntax:

this.props.store.dispatch(*insert action*);

We can then pass this event handler as a prop like so:

<BookCard
key = { book }
stateProps = { stateProps }
dispatchAction = {this.dispatchAction.bind(this)}
/>

In BookCard.js, the icons can call the event handler like so:

<i onClick={() => this.props.dispatchAction("TRASH")} className="icon fa fa-trash" aria-hidden="true"></i><i onClick={() => this.props.dispatchAction("PLUS")} className="icon fa fa-plus" aria-hidden="true"></i>

Note that we have to use {() => …} for passing parameters.

To finish off our add and delete operations, we just have to make sure our container component (Books.js) is subscribed to our store that our component will be re-rendered when this happens.

To do this, we can add a componentWillMount() lifecycle hook where we can add the subscription. We can force or component to re-render by using this.forceUpdate.bind(this) (see official React documentation):

componentWillMount() {
this.props.store.subscribe(this.forceUpdate.bind(this));
}

Now, we can test this in the local host:

Finally!

Implementing Edit Operations

With the add and delete operations under our belt, the edit operation should be a lot less effort. We are going to make things easy and just edit the book with predefined information.

Open our reducer found in BooksApp.js.

In our reducer, we want to add the logic to create a copy of the current state and replace the book information with properties in our action object (we will create this next).

Here’s how we can do that:

switch(action.type) {
case 'ADD_BOOK':
let incremented = Object.assign({}, state)
incremented.books.push(incremented.books.length)
return incremented
case 'DELETE_BOOK':
let decremented = Object.assign({}, state)
decremented.books.pop()
return decremented
case 'EDIT_BOOK':
let edited = Object.assign({}, state, {
cover: action.cover,
title: action.title,
author: action.author,
link: action.link
})
return edited
default:
return state
}

This is similar to how we handled actions in the reducer of our first Redux example. In the Object.assign , we update the state’s properties with the properties defined in our action.

Let’s code the action creator in a new file called EditBook.js in the actions folder.

Unlike our previous actions, we will have more than a type defined in our action. We also have properties for the cover, title, author, and link as our reducer is set to handle:

//define action within an action creator
function EditBook() {
const EDIT_BOOK = 'EDIT_BOOK'
return {
type: EDIT_BOOK,
cover: "https://s3.amazonaws.com/titlepages.leanpub.com/learnreactvr/hero?1496886273",
title: "Learn React VR",
author: "Mike Mangialardi",
link: "https://leanpub.com/learnreactvr"
}
}
export default EditBook

The final piece of this edit implementation is to dispatch this action on the click of the pencil icon.

Open Books.js and let’s import the edit action:

import EditBook from '../../actions/EditBook';

Then, let’s update our dispatchAction event handler to handle a call from the pencil icon:

dispatchAction (input) {
switch (input) {
case "TRASH":
this.props.store.dispatch(DeleteBook());
break;
case "PLUS":
this.props.store.dispatch(AddBook());
break;
case "PENCIL":
this.props.store.dispatch(EditBook());
break;
}
}

Finally, we add the call from BookCard.js:

<i onClick={() => this.props.dispatchAction("PENCIL")} className="icon fa fa-pencil" aria-hidden="true"></i>

Save and let’s test this is the local host:

Round of applause! We have completed our first React & Redux application.

Final Code

Available on GitHub.

Concluding Thoughts

Although our data was manually predefined (no API or database), this chapter was a great introduction into a React and Redux implementation. We will be building off of this and explore fetching data from an API in the next chapter. Eventually, we will be creating our own database and API service to finish off this Book Card project.

Chapter 4

Chapter 4 is now available.

Buy the Official Ebook

If you would like to support the author and receive a PDF, EPUB, and/or MOBI copy of the book, please purchase the official ebook.

Cheers,
Mike Mangialardi

--

--