You are on page 1of 1

Upgrade

A Guide For Building A React Redux


CRUD App
rajaraodv Follow
Mar 6, 2016 · 10 min read

Building a single-page CRUD app using React and Redux can be challenging
because you’ll have to deal w/ new techniques and terms like “Reducers”,
“Actions”, “Middlewares”, “Stores” and so on.

Perhaps the trickiest part is making async requests and handling responses.
While there are many examples, there is no well established pattern for
making async requests and handling responses in Redux apps(just yet).

In this blog I’ll provide a general approach on how to build a Blog app
that has 3 pages and show navigate b/w them.

Further, I’ll also establish a pattern for making async requests and
handling four async states: “loading”, “success”, “error” and “success-
and-navigate”.

Source code: https://github.com/rajaraodv/react-redux-blog

Live App: https://protected-escarpment-79486.herokuapp.com/

Twitter: https://twitter.com/rajaraodv (@rajaraodv)

Let’s get started.

STEP 1 — Write Detailed Mocks For Each Page And


Phases.
In our app we have 3 pages: An Index page that shows a list of Posts, a Post
details page and a New Post page.

Each page has “Success”, “Loading” and “Error” phases because they all
make AJAX calls to load/delete posts, so we need to mock those things as
well.

1.1 Success Phase — Detailed Mocks when things are working

Note: You can click on the pictures to Zoom and read

1.2 Loading Phase — Detailed Mocks when they are loading

1.3 Error Phase — Detailed Mocks when there is an Error

STEP 2 — Divide Each Page Into Components


Look at all the phases of each page and roughly divide each page into
components based on “purpose” and based on physical location.

This helps you identify reusable components across different pages and also
any additional ones in a specific phase. For example, you may need a
“Spinner” or an “Error” component for different phases.

Note: this doesn’t need to be perfect. You can make changes later on.

2.1 — Success Phase: Divide Each Page Into Components


1. Index page: 1. Shows list of posts, 2. Allows navigating to Post form
page to create new post. So we end up w/ PostsList and Header
components.

2. Post details page: 1. Shows details of the post, 2. Allows navigating


back to Index page 3. Index page. So we end up with PostDetails and
Header components.

3. New Post page: 1. Allows creating posts and 2. allows navigating back to
Index. Again we end up with PostForm and Header component.

Notice that we can reuse Header across all 3 pages because of the physical
location. So we end up with four components (instead of 6): 1. PostsList, 2.
PostDetails 3. PostForm and 4. Header components.

2.2 — Loading Phase: Divide Each Page Into Components


If you look at the mock, we are simply displaying “loading..” text in each
page and not using some fancy spinner or “toast”. So we don’t have any
more components.

2.3 — Error Phase: Divide Each Page Into Components


If you look at the mock, we are simply throwing an alert popup and not
using any custom modals. So we don’t have any more components.

So net-net, we have 4 components (1. PostsList, 2. PostDetails 3.


PostForm and 4. Header)

Redux Terms:
Redux Terms — “Actions” And “States”
Every component does two things:
1. Listen to the user and server events and send them to JS functions. In
Redux, events are represented as a JSON object called “Actions”.

{"type": "FETCH_POST", "id": 1234} // <-- Action

2. Render DOM based on some data. This data is called a“state”, which is
also a JSON object.

{"post": {"id": 1234, "title": "My Redux Post"}} // <-- state

Redux Terms — “Action Creators”


These are functions that listen to DOM or server events and return formal
JSON “Action” object.

function fetchPost(id) {
return {
type: FETCH_POST,
result: makeServerRequest("http://postsServer.com/api/id")
};
}

See Action Creators for our app.

Redux Terms — “Dispatching an Action”


Redux provides a function called “dispatch” which allows us to pass the
“Action” JSON object to all other components. Dispatching an Action means
simply calling the dispatch function w/ the action JSON object.

//Call the "Action Creator" w/ post's id and then use it's return
//value (Action JSON object) to finally dispatch it to "reducers"

dispatch(fetchPost(id)) or dispatch({type:"FETCH_POST", id:1234})

The components calls Action creators to receive Actions and then dispatches the
actions. Redux then send the actions to “Reducers”

Redux Terms — “Reducers”


Reducers are functions that take an Action and the current state that Top highlight

was sent to them via “dispatch”, apply action to the current state and
return a new state. And Redux re-renders all components whenever there
is a new state.

//If the action is FETCH_POST_SUCCESS, return a new "activePost"


//state w/ new post)
case FETCH_POST_SUCCESS:
return {activePost: {post: action.payload.data, error:null,
loading: false}};

See Reducers “reducer_posts.js” and main “index.js” (this combines multiple


reducers into one)

OK, before we go ahead to step 3, let’s understand how to deal with


Async Actions because every page makes AJAX calls.

PATTERN: Dealing With Async Actions


If component is loading an object(e.g. list of Posts) via AJAX call to the
server, that object’s state should keep track of all the potential states. Initial
state for such objects should look like: {objName: {obj:null, loading: false,
error:null}}.

Further, such components should dispatch up to 4 actions such as


“FETCH_OBJ”(for loading), “FETCH_OBJ_SUCCESS”,
“FETCH_OBJ_FAILURE” and “OBJ_RESET”(to cleanup dirty previous
state).

For example, if we are loading list of posts..

Note: You can click on the pictures to zoom and read

Initial State: Initial state should look like,

{postsList:{posts:[], loading:false, error:null}}

Actions:

1. FETCH_OBJ — Dispatch this to make the server request and also let
other components know we are loading. This helps current/other
components show “loading” or hide or do something.

dispatch({“type”: “FETCH_POSTS”, loading: true})

Once Redux gets this and passes it through reducers, the new state will look
something like:

{postList: {posts:null, error: null, loading: true}}

2. FETCH_OBJ_SUCCESS: Dispatch this when you get successful response.


This is to show the actual data and also to cancel “loading”

dispatch({"type": "FETCH_POSTS_SUCCESS", "posts":[post1, post2])

Once Redux gets this and passes it through reducers, the new state will look
something like:

{postsList:{posts:[post1, post2], error:null, loading: false}}

3.FETCH_OBJ_FAILURE: Dispatch this when you get a failed response.


This is to show some error message and also to cancel “loading”.

dispatch({"type": "FETCH_POSTS_FAILURE", "error": "Error message"})

Once Redux gets this and passes it through reducers, the new state will look
something like:

{postList:{posts:null, error:{msg: "Error msg"}, loading: false}}

4.RESET_OBJ: Dispatch this to reset the component’s state after


success/failure. This is optional but can be useful when you want to
reuse a “dirty” component from previous AJAX request.

dispatch({"type": "RESET_POST", loading: false, "post": null,


"error": "Error message"})

Once Redux gets this and passes it through reducers, the new state will look
something like:

{postList:{post:null, error:null, loading: false}}

STEP 3 — List State and Actions For Each


Component (AND For Each Phase)
Take a look at each component one by one and each phase and list of state
and actions.

We have 4 components: 1. PostsList, 2. PostDetails 3. PostForm and 4.


Header components.

3.1 PostList Component — List State And Actions

States:

List out various data that may change the display of the component in all
phases of the component.

1. Shows list of Posts. Let’s call the state as “posts” (an array).

2. Shows “Loading..”, if it’s in the processing fetching the posts. Let’s call
this state “loading”(boolean)

3. Shows “Error” if there is an error. Let’s call this state as “error”(null or


error info).

Since all the above are related to PostList, let’s put them in a single state
object called postList.

{ postsList: {posts: [], error:null, loading: false} //initial state

Actions:

This component makes a “AJAX” call to load posts, so we’ll use the above
mentioned pattern and create 4 actions.

1.Asks server for list of posts. Let’s call this action as: “FETCH_POSTS”.

export function fetchPosts() {


const request = axios.get(`${ROOT_URL}/posts`);

return {
type: FETCH_POSTS,
payload: request
};
}

2.Tells every component that it received posts (success case). Let’s call this
“FETCH_POSTS_SUCCESS”

export function fetchPostsSuccess(posts) {


return {
type: FETCH_POSTS_SUCCESS,
payload: posts
};
}

3.Tells every component that there was an error(failure case). Let’s call this
“FETCH_POSTS_FAILURE”

export function fetchPostsFailure(error) {


return {
type: FETCH_POSTS_FAILURE,
payload: error
};
}

4. Resetting data is not required because this is the 1st page (you’ll see how
this is useful in other 2 pages)

3.2 PostDetails Component — List State And Actions

Note: You can click on the pictures to zoom and read

3.3 PostForm Component — State And Actions

3.4 Header Component — List State And Actions

STEP 4 — Create Action Creators For Each Action


We have a total of 12 actions(4 actions x 3 pages), create action creators
for each one. Please see the source code here.

//Example Action creators...

export function fetchPosts() {


const request = axios.get(`${ROOT_URL}/posts`);

return {
type: FETCH_POSTS,
payload: request
};
}

export function fetchPostsSuccess(posts) {


return {
type: FETCH_POSTS_SUCCESS,
payload: posts
};
}
...

Redux Term: “Reducers”


Reducers are functions that take “state” from Redux and “action” JSON
object and returns a new “state” to be stored back in Redux.

1. Reducer functions are called by the “Container” containers when there is


a user or server action.
2. If the reducer changes the state, Redux passes the new state to each
component and React re-renders each component

The below function takes the current "postsList" inside "...state"


and merges new "postList" and creates a **new** state(json), if the
action is "FECTH_POSTS_SUCCESS"

case FETCH_POSTS_SUCCESS:
return { …state, postsList: {posts: action.payload, error:null,
loading: false}
};

STEP 5 — Write Reducers For Each Action


We have 12 actions, we need to write reducers for each one of them.

Please look at the source code for details here.

Redux Term: “Presentational” and “Container”


Components
Keeping React and Redux logic inside each component can make it messy,
so Redux recommends creating a dummy presentation only component
called “Presentational” component and a parent wrapper component called
“Container” component that deals w/ Redux, dispatch “Actions” and more.

The parent Container then passes the data to the presentational


component, handle events, deal with React on behalf of Presentational
component.

Legend: Yellow dotted lines = “Presentational” components. Black dotted lines


= “Container” components.

STEP 6 — Implement Every Presentational


Component
We have 4 components: PostsList, PostDetails, PostForm and Header.
Let’s create presentational components for each one.

6.1 Implement Presentational Component — PostsList

Note: You can click on the pictures to zoom and read

6.2 Implement Presentational Component — PostDetails

6.3 Implement Presentational Component — PostForm

Note: In the actual code, I am using the awesome redux-form library for form-
validation. I’ll blog about it in a different post.

6.4 Implement Presentational Component — Header

Note: You can click on the pictures to zoom and read

STEP 7 — Create Container Component For


Some/All Presentational Component
We have 4 components: PostList, PostDetails, PostForm and Header. Let’s
create container components for each one.

7.1 Create Container Component — PostsListContainer

7.2 Create Container Component — PostDetailsContainer

7.3 Create Container Component — PostFormContainer

7.4 Create Container Component — HeaderContainer

STEP 8 — Finally Bring Them All Together


Below code is a simplified version of wiring everything together. Please see
source code of the main index.js and reducers.js to get started.

import React from 'react'; <-- Main React lib


import ReactDOM from 'react-dom'; <-- Main React DOM lib
import { Provider } from 'react-redux';<-- Injects Redux to comps
import { createStore, applyMiddleware } from 'redux';<- Redux
import { Router, browserHistory } from 'react-router';<- Navigation
import reducers from './reducers'; <- Import reducers
import promise from 'redux-promise';

//Configure middleware w/ redux-promise for AJAX requests


const createStoreWithMiddleware = applyMiddleware(
promise
)(createStore);

const store = createStoreWithMiddleware(reducers);

ReactDOM.render(
<Provider store={store}> <- Inject global redux state to comps
<Router history={browserHistory}>
<Route path=”/” component={App}> <- Wrapper for all pages
<IndexRoute component={PostsIndex} /> <-wrapper Index page
<Route path=”posts/new” component={PostsNew} /> <- New page
<Route path=”posts/:id” component={PostsShow} /> <-Details
</Route>
</Router>
</Provider>
, document.getElementById('body'));

That’s it for now!

My Other Blogs
LATEST:

1. [Video course] The Inner workings of the Browser — for JavaScript & Web
Developers Use code: INNER15 and get 50% off!

Functional Programming
1. JavaScript Is Turing Complete — Explained

2. Functional Programming In JS — With Practical Examples (Part 1)

3. Functional Programming In JS — With Practical Examples (Part 2)

4. Why Redux Need Reducers To Be “Pure Functions”

ES6
1. 5 JavaScript “Bad” Parts That Are Fixed In ES6

WebPack
1. Webpack — The Confusing Parts

2. Webpack & Hot Module Replacement [HMR]

3. Webpack’s HMR And React-Hot-Loader — The Missing Manual

Draft.js
1. Why Draft.js And Why You Should Contribute

2. How Draft.js Represents Rich Text Data

React And Redux :


1. Step by Step Guide To Building React Redux Apps

2. A Guide For Building A React Redux CRUD App (3-page app)

3. Using Middlewares In React Redux Apps

4. Adding A Robust Form Validation To React Redux Apps

5. Securing React Redux Apps With JWT Tokens

6. Handling Transactional Emails In React Redux Apps

7. The Anatomy Of A React Redux App

8. Why Redux Need Reducers To Be “Pure Functions”

Salesforce
1. Developing React Redux Apps In Salesforce’s Visualforce

🎉🎉🎉 If you like this post, please share it on Twitter.


https://twitter.com/rajaraodv 🎉🎉🎉

Thanks for reading!! 😀🙏

React Redux JavaScript Tech Technology

5.5K claps

WRITTEN BY

rajaraodv Follow

Trying to make Web development simple. Former Developer


Advocate @Salesforce, VMware (node.js); Engineer @ Yahoo,
Zimbra. Twitter: @rajaraodv

See responses (55)

Discover Medium Make Medium yours Become a member


Welcome to a place where words matter. On Medium, smart Follow all the topics you care about, and we’ll deliver the Get unlimited access to the best stories on Medium — and
voices and original ideas take center stage - with no ads in best stories for you to your homepage and inbox. Explore support writers while you’re at it. Just $5/month. Upgrade
sight. Watch

About Help Legal

You might also like