Showcase of React + Redux Web Application Development

Jian Li JavaScript, React, Single-Page Application, Tutorial Leave a Comment

Attention: The following article was published over 7 years ago, and the information provided may be aged or outdated. Please keep that in mind as you read the post.

In the last few years, React has continuously gained popularity for the development of web applications. At Keyhole, we have several blogs talking about React and related technologies, including React, Formik, react-router, and many others.

So why would we need Redux? Quite often when we develop applications, we start with small pieces. As the business requirements change, new features/modules/components are added/removed/updated. Particularly in enterprise applications, you may end up with a deep hierarchy of parent-child relationships.

In a React application, parent component-states are passed down to its child component as property. Application states can be changed in many different places. If not managed perfectly (and, in many cases, it’s not), your system can behave differently than expected. It can become increasingly difficult for development, debugging, production support and code maintenance.

This is where Redux comes into play. Using Redux with React solves this common problem with the concepts of central data store & application state.

In this blog, I’ll talk about Redux and explain how it can benefit React front-end development. I’ll provide an introduction to using Redux with React and show a demonstration of reconstructing an example React application to React + Redux.

Our Example

The application that our example will begin with is the Keyhole “Now Playing” React application. The repository is located here: https://github.com/in-the-keyhole/khs-react-course.

I’ll re-construct this React application into two projects. The first project will be the back-end server application which will handle all the typical business in the server end, like registration, authentication, database operation, etc. I’ll use MongoDB to persistent data and Node.js for REST API development. You can also reference RESTful API development to the Github repository open source khs-convo, released by Keyhole Software.

The second project will be pure front-end development, which will React with Redux for state management. React with Redux integration is the focus of this blog.

If you are eager to see the final project, git clone these two repos: https://github.com/in-the-keyhole/khs-movies-server.git and https://github.com/in-the-keyhole/khs-movies-client.git. Construct a local build by using the following instructions provided in README; you can take a look of the running application in your browser at http://locahost:3000.

Introduction to Redux

So what is Redux and how does it relate to React?

Redux is a predictable state container for JavaScript applications. In its simplest form, it is a library to manage the state of any JavaScript application.

The following figure demonstrates the React + Redux flow.

The right side of the figure as shows the key element for Redux:

  • Store: holds all application store into a single object tree.
  • Reducers: only way to change state by emitting an action.
  • Actions: specify anything that could change the application state.

The left side shows the integration of Redux with React:

  • Provider: makes the application state contained in store available to container.
  • Containers Component: responsible for an external service call to retrieve application data, container also maps the state and dispatches action to component.
  • Presentational Components: the presentation layer.

This is the overall flow in a React + Redux application. Now let’s go through each individual piece with examples.

On the Redux Side

Store

To have Redux manage an application’s state, all state must be contained within a single object. At the minimum, to create a store, you need to have root reducer and initial state.

 
'react-router-redux' and initial state object. 

import {createStore} from 'redux'
import {  routerReducer } from 'react-router-redux'
const initialState = {
   movies: []
};
const store = createStore(rootReducer, initialState )
export default store;

With this configuration, the state movies can be managed by Redux store. As you can see, the initial state is an empty array; we will need to create Reducer to change the movies’ state.

Reducers

Reducers are responsible for changing application state with the emitting of actions.

As you can imagine, the functions for a Movies Reducer are to retrieve movies and perform searches on the movies you retrieved. Reducers are a pure function. In our example, it returns the action payload based on its type. I’ll show you later on how to create action.

  
import {c} from '../constants'
const movies = (state = {
}, action) => {
   switch (action.type) {
       case c.LOAD_MOVIES:
           return action.payload;
       case c.SEARCH_MOVIES:
           return action.payload;
       default:
           return state
   }
}
export default movies

Actions

Anything that can cause application state change must happen in Actions.

We have previously identified two type of actions that changes state of movies: LOAD_MOVIES and SEARCH_MOVIES. This is the Load movies action implementation; a similar implementation for search action could be found on git repo here.

 
import {fetChMovies, changeRating} from '../services/movie.js';
import {c} from '../constants';

export function preloadMovies() {
 return (dispatch) => {
   loadMovies()(dispatch);
 };
}
function loadMovies(dispatch) {
 return (dispatch) => {
   fetChMovies().then((movies) => {
     allMovies = movies;
     dispatch(loadTheMovies(movies));
   });
 };
}
function loadTheMovies(movies) {
 return ({type: c.LOAD_MOVIES, payload: movies});
}
export const movieActions = {
 preloadMovies 
}
export default movieActions; 

In this example, I have, added a service layer of fetchMovies by calling RESTFul API that is published by khs-server application. You can take a look at the implementation details here. By calling dispatch(loadTheMovies(movies), the movie Reducer will update the movies state.

On the React Side

So by this point, we have demonstrated that application state can be managed by Redux. We have not, however, yet integrated state change with React. React and Redux can be integrated together with the help of provider offered by the react-redux package.

Provider

The Provider glues the Redux store together with the React component. This means that the application state information in the single store is available for React components.

For a React application, you must define the render of the root application element like this:

 
const element = <App />
ReactDOM.render(element, document.getElementById('root'))

In order to have Redux work with React, you will need to do this:

 
const element = <App />
ReactDOM.render(
 <Provider store={store}>
 <ConnectedRouter history={history}>
   <div  className ="container" id="wrapper">
     <div>
       <App/>
   </div>
 </ConnectedRouter>
</Provider>, document.getElementById('root'))

As you can see, the React application is now managed by the provider which is associated to the Redux store. ConnectedRouter from react-router-redux is also used to provide application routing.

Through Provider, the React component is able to refer to the state information contained in Redux store. Based on the different roles in integrating with Redux, React component can be separated into two categories: presentational and container components.

Presentational Components
  • For data presentation
  • Reads data from component property
  • Invokes callbacks from props
  • Unaware of Redux
  • Container Components
  • Responsible for data fetch and update state
  • Gets state from store
  • Dispatches redux actions
  • Aware of redux
  • Presentational Component: MovieList

    Let’s demonstrate this. The presentation component MovieList is responsible for displaying the movie’s information.

     
    import React from 'react'
    import Movie from './Movie.js'
    const MovieList = ({
     Movies 
    }) => {
     return (
       <div className="movie-container">
         <br/>
         <div>
           <ul>
             {movies.map(movie => <li key={movie.id}>
               <Movie title={movie.title} poster={"/" + movie.poster_path} id={movie.id}/>
             </li>)}
           </ul>
         </div>
       </div>
     )
    }
    
    export default MovieList;
    

    Container Component: MoviesContainer

    The container component called MoviesContainer is used to wrap up the presentation component movies.

     
    import {connect} from 'react-redux'
    import {Component} from 'react'
    import {bindActionCreators} from 'redux'
    import React from 'react'
    import {withRouter} from 'react-router-dom'
    import MovieList from '../ui/MovieList.js'
    import MovieActions from '../../actions/movie.js'
    
    class MoviesContainer  extends Component {
       componentWillMount() {
           this.props.preloadMovies();
       }
       render() {
           return <MovieList movies={this.props.movies/>
       }
    }
    const mapStateToProps = (state, props) => ({movies: state.movies })
    const mapDispatchToProps = dispatch => bindActionCreators(MovieActions,dispatch);
    
    export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MoviesContainer))
    

    The container component MoviesContainer is responsible for data fetching by dispatching reducer action as followed: this.props.preloadMovies. You may be wondering why preloadMovies is a property here and not an action, and how it could work with Redux?

    Connect from the react-redux package does the trick. Connect is used to map the store’s state and dispatch to the property of a component. As you can see from this example, the state movies is passed as a property to the presentation component.

    Conclusion

    What I discussed above are the main components for pre-loading movies. The git repository provides more features, like user registration, login, logout, the ability to search for movies by name, rating movies, to list a few examples. Please check out those features for further reference.

    You will quickly realize that the implementation pattern is consistent when a new feature is added and the responsibilities for each component are clearly defined. Most importantly, application state change is unidirectional, which means its more predictable, easier to manage, and the code is more maintainable.

    Redux is designed to manage state for single-page applications. We have discussed how the unification of React + Redux provides a powerful tool for web application development. We have increasingly seen more Keyhole clients choosing the React route for web development front-end technology. I personally recommend they also integrate Redux to manage state in the earliest stage of development.

    0 0 votes
    Article Rating
    Subscribe
    Notify of
    guest

    0 Comments
    Oldest
    Newest Most Voted
    Inline Feedbacks
    View all comments