dcsimg
September 26, 2018
Hot Topics:

Manage State in React Apps with Redux

  • August 29, 2018
  • By Robert Gravelle
  • Send Email »
  • More Articles »

Not so long ago, developing front-end applications seemed like a joke to a lot of professional programmers. Now, the ever-increasing complexity of front-end applications can occasionally overwhelm even the most seasoned pro. Modern frameworks—such as Angular, React, and Vue—have done a great job at making developers' lives easier in that regard. Now, you can add Redux to that list. It helps you manage application state on different platforms, be it client, server, or native. You can use Redux together with React, or with any other view library.

Can you build modern Web apps without Redux? Of course, but, in larger apps with a lot of moving pieces, state management becomes a huge concern. Redux will handle it without performance degradation. It also includes a lot of nice perks, such as logging, hot reloading, universal apps, record and replay, and more.

In today's article, we'll learn how to manage application state in a very simple React app that allows the user set the background color of a DIV element.

The Three Principles Of Redux

The first thing to know about Redux is, that unlike other frameworks like Flux, which employs a separate store for each app module, Redux holds application state in a single store. There is an only one way to change the state, and that is to emit an action, which is an object describing what happened. To specify how actions transform the state, you write reducers.

Redux espouses three guiding principles:

  • Having to maintain the one store, we can say that it is "the only source of truth."
  • The state must be read-only.
  • Changes are made with pure functions (Reducers).

The Demo

We will use Redux to keep track of the current color within our demo app. Before we do, keep in mind that using Redux in such a trivial app may seem like more trouble than it's worth. That is probably true, but in a complex real-world app, Redux's single store architecture can make state management a lot easier and robust than it would be otherwise.

Here's what the completed app will look like:

The completed app
Figure 1: The completed app

The first step is of course to generate the basic React project using the "create-react-app react-Redux-color-demo" command. create-react-app is the easiest way to create a new React app; just provide the app name and it will scaffold a new app for you. If you don't have it, you can install it globally using the "npm install -g create-react-app" command:

PS I:\My Documents\articles\codeguru\Redux> create-react-app
   react-Redux-color-demo

Creating a new React app in I:\My Documents\articles\codeguru\
   Redux\react-Redux-color-demo.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts...


> uglifyjs-webpack-plugin@0.4.6 postinstall I:\My Documents\
   articles\codeguru\Redux\react-Redux-color-demo\node_modules\
   uglifyjs-webpack-plugin
> node lib/post_install.js

+ react-scripts@1.1.4
+ react@16.4.2
+ react-dom@16.4.2
added 1320 packages in 155.65s

Success! Created react-Redux-color-demo at I:\My Documents\
   articles\codeguru\Redux\react-Redux-color-demo
Inside that directory, you can run several commands:

   npm start
      Starts the development server.

   npm run build
      Bundles the app into static files for production.

   npm test
      Starts the test runner.

   npm run eject
      Removes this tool and copies build dependencies,
         configuration files and scripts into the app directory.
         If you do this, you can't go back!

We suggest that you begin by typing:

   cd react-Redux-color-demo
   npm start

Happy hacking!
PS I:\My Documents\articles\codeguru\Redux>

Next, we need to install the redux and react-redux libraries. Although Redux is framework agnostic, the react-redux library adds the special connect() function. It extracts the state and dispatch actions from the Redux store, and wraps them as props.

PS C:\Users\blackjacques\my-first-react-app> npm install Redux
   react-Redux
npm WARN ajv-keywords@3.2.0 requires a peer of ajv@^6.0.0 but none
   is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4
   (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform
   for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"}
   (current: {"os":"win32","arch":"x64"})

+ redux@4.0.0
+ react-redux@5.0.7
added 3 packages and updated 1 package in 8.768s

You might get a message or two about a library requiring a peer of such-and-such. In those cases, just install what npm is asking for, as follows:

PS C:\Users\blackjacques\my-first-react-app>
   npm install ajv@^6.0.0
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4
   (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform
   for fsevents@1.2.4: wanted {"os":"darwin","arch":"any"}
   (current: {"os":"win32","arch":"x64"})

+ ajv@6.0.0
added 4 packages and updated 1 package in 8.531s

To test the app, cd into the "react-Redux-color-demo" project directory and issue the "npm start" command. The app then should launch in your default browser:

The application is launching
Figure 2: The application is launching

Defining the Colors

We'll put the colors in an object so that we can refer to them using named constants; for example, Colors.RED. Save this code to a file named "Colors.js" under src/colors in your project:

const Colors = {
   GRAY:   'gray',
   RED:    'red',
   GREEN:  'green'
};

export default Colors;

The Color Component

The ColorComponent class renders our buttons and color container in the app. Beyond that, it also implements the connect() function. It provides many useful optimizations for generating container components that prevent unnecessary re-renders. To use connect(), you need to define a special function called 'mapStateToProps' that describes how to transform the current Redux store state into the props you want to pass to a presentational component that you are wrapping.

In the updateBackgroundColor() function, you'll notice the dispatch method. It's a member of the store object that dispatches an action to trigger an update to the store. An action is a regular JavaScript object that usually has two properties: type and payload. The payload property is where we can pass any data that we want to have dispatched:

import React from "react";
import { connect } from 'react-redux';
import Colors from "../constants/Colors";

class ColorComponent extends React.Component {

   updateBackgroundColor = (newColor) => {
      this.props.dispatch({ type: 'CHANGE_COLOR',
         color: newColor });
   }

   render() {
      return (
         <div>
            <button onClick={() =>
               {this.updateBackgroundColor(Colors.RED)}}>RED
            </button>
            <button onClick={() =>
               {this.updateBackgroundColor(Colors.GREEN)}}>GREEN
            </button>
            <div className="color-container"
               style={{backgroundColor: this.props.color,
                       width: '200px', height: '200px'}} />
         </div>
      )
   }
}

function mapStateToProps(state) {
   return {
      color: state.color
   };
}

export default connect(mapStateToProps)(ColorComponent);

Add the preceding code to the ColorComponent.js file under src/components.

The index.js File

The index.js script creates the Redux store and assigns it to the app via the Provider tag. By including the App creation code here, you'll find that the App.js file is now obsolete.

The createStore function requires a reducer function. It's a pure JS/ES6 function that takes the previous state and an action, and returns the next state. In our case, it returns the action.color that we passed to the dispatcher to designate it as the new color:

import React from 'react';
import { render } from 'react-dom';
import ColorComponent from './components/ColorComponent';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import registerServiceWorker from './registerServiceWorker';
import Colors from './constants/Colors';

const initialState = {
   color: Colors.GRAY
};

function reducer(state = initialState, action) {
   switch(action.type) {
      case 'CHANGE_COLOR':
         return {
            color: action.color
      };
      default:
         return state;
   }
}

const store = createStore(reducer);

const App = () => (
   <Provider store={store}>
   <ColorComponent/>
   </Provider>
);

render(<App />, document.getElementById('root'));
registerServiceWorker();

The three files that we worked on here are hosted on GitHub.

Conclusion

Redux's use of a single store, actions that represent the facts about "what happened," and reducers that update the state according to those actions makes managing state in complex applications both easier and less error prone. In upcoming articles, we'll explore these benefits in more complex apps.






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

By submitting your information, you agree that developer.com may send you developer offers via email, phone and text message, as well as email offers about other products and services that developer believes may be of interest to you. developer will process your information in accordance with the Quinstreet Privacy Policy.

Sitemap

Thanks for your registration, follow us on our social networks to keep up-to-date