Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Use Redux in Your React.js App in Just 10 Minutes

DZone's Guide to

How to Use Redux in Your React.js App in Just 10 Minutes

In this post, we will learn the principles behind Redux and how to use Redux in a React.js-based application. Let's get started!

· Web Dev Zone ·
Free Resource

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

If you have decided to use Redux as your state management library, now you actually have done the hard part. Deciding which library to use. Everything else is very easy and fast. Follow along to create a to-do app with Redux in just 5 minutes.

The Idea Behind Redux

You have mainly three components: store, reducer, and actions.

As per the Redux docs:

A Store holds the whole state [tree] of your application. The only way to change the state inside it is to dispatch an action on it.

Actions are payloads of information that send data from your application to your store. They are the only source of information for the store.

We will define two actions, createItem and deleteItem.

Reducers specify how the application’s state changes in response to actions sent to the store. Remember that actions only describe what happened, but don’t describe how the application’s state changes.

We will create one reducer just like a table in a SQL DB, but you can create more if you need to.

Tutorial

Step 1

Create a new React app using CRA (create-react-app).

create-react-app todo-app

Step 2

Install dependencies.

npm install lodash @material-ui/core @material-ui/icons react-redux redux redux-logger

Step 3

If you want to learn an efficient way to store your files, use the ducks file structure. But, for simplicity, we will be using a simple file structure.

Create a new folder inside src named “modules.”

Create three files inside the folder: action.js, reducer.js, store.js

Actions are simple objects with one mandatory property type. You can dispatch actions from your component to send data to the state store.

action.js

// types of action
const Types = {
  CREATE_ITEM: "CREATE_ITEM",
  DELETE_ITEM: "DELETE_ITEM"
};
// actions
const createItem = task => ({
  type: Types.CREATE_ITEM,
  payload: task
});

const deleteItem = id => ({
  type: Types.DELETE_ITEM,
  payload: id
});

export default {
  createItem,
  deleteItem,
  Types
};


Ideally, you should create another file for your action types.

import ACTIONS from "./action";
import _ from "lodash";

const defaultState = {
  items: []
};

const todoReducer = (state = defaultState, action) => {
  switch (action.type) {
    case ACTIONS.Types.CREATE_ITEM: {
      console.log(action);

      let item = action.payload;
      let newItem = { id: state.items.length + 1, description: item };
      let newState = _.cloneDeep(state);
      newState.items.push(newItem);
      return newState;
    }

    case ACTIONS.Types.DELETE_ITEM: {
      let newState = _.cloneDeep(state);
      let index = _.findIndex(newState.items, { id: action.payload });
      newState.items.splice(index, 1);
      return newState;
    }

    default:
      return state;
  }
};

export default todoReducer;

store.js

import { createStore, applyMiddleware } from "redux";

// Logger with default options
import logger from "redux-logger";

import reducer from "./reducer";

export default function configureStore(initialState) {
  const store = createStore(reducer, initialState, applyMiddleware(logger));
  return store;
}


Step 4

Create a new todo.js file in a new folder inside src named “pages.” This will contain our todo list component. This example is focused on Redux so we won’t try to create a component/containers. We will have our entire app in this file only.

Create the UI with a form and a list to show the tasks.

todo.js

import React, { Component } from "react";
import {
  withStyles,
  List,
  ListItem,
  ListItemSecondaryAction,
  ListItemText,
  IconButton,
  Grid,
  TextField,
  Button,
  FormControl
} from "@material-ui/core";
import DeleteIcon from "@material-ui/icons/Delete";

const styles = theme => ({
  root: {
    flexGrow: 1,
    maxWidth: 752
  },
  demo: {
    backgroundColor: theme.palette.background.paper
  },
  title: {
    margin: `${theme.spacing.unit * 4}px 0 ${theme.spacing.unit * 2}px`
  }
});

class ToDO extends Component {
  state = {};

  generate = () => {
    return this.props.items.map(item => (
      <ListItem key={item.id}>
        <ListItemText primary={item.description} />
        <ListItemSecondaryAction>
          <IconButton
            aria-label="Delete"
            onClick={this.handleDelete}
            value={item.id}
          >
            <DeleteIcon />
          </IconButton>
        </ListItemSecondaryAction>
      </ListItem>
    ));
  };

  handleSubmit = event => {
    // console.log(this.state.item);
    this.setState({ item: "" });
    if (this.state.item !== "") {
      // add the task to store

    }
    event.preventDefault();
  };
  handleDelete = event => {
    //delete the task from the store

  };
  handleChange = event => {
    this.setState({
      [event.target.name]: event.target.value
    });
  };

  render() {
    const { classes } = this.props;

    return (
      <div>
        <div>
          <form noValidate autoComplete="off" onSubmit={this.handleSubmit}>
            <FormControl>
              <TextField
                label="New Task"
                id="margin-dense"
                value={this.state.item}
                className={classes.textField}
                margin="dense"
                name="item"
                onChange={this.handleChange}
              />
            </FormControl>
            <FormControl>
              <Button>Add</Button>
            </FormControl>
          </form>
        </div>
        <div>
          <Grid item container justify="space-evenly" alignItems="center">
            <div className={classes.demo}>
              <List dense={false}>{this.generate()}</List>
            </div>
          </Grid>
        </div>
      </div>
    );
  }
}

export default withStyles(styles)(ToDO);

Step 5

It’s time to connect our todo component to the Redux store.

Open your app.js file and add the Redux provider so all of the child properties can access the store.

import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import ToDO from "./pages/todo";
import { Provider as ReduxProvider } from "react-redux";
import configureStore from "./modules/store";

const reduxStore = configureStore(window.REDUX_INITIAL_DATA);

class App extends Component {
  render() {
    return (
      <ReduxProvider store={reduxStore}>
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <h1 className="App-title">ToDo Redux app</h1>
          </header>
          <ToDO />
        </div>
      </ReduxProvider>
    );
  }
}

export default App;

Inside your todo.js file, connect it with the store using the connect component from react-redux. Add these at the end of the file in todo.js.

Now, the items from store will be available in the component’s props. Also, the other two functions (actions) will be available in props.

import ACTIONS from "../modules/action";
import { connect } from "react-redux";

const mapStateToProps = state => ({
  items: state.items
});

const mapDispatchToProps = dispatch => ({
  createItem: item => dispatch(ACTIONS.createItem(item)),
  deleteItem: id => dispatch(ACTIONS.deleteItem(id))
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(withStyles(styles)(ToDO));

Lastly, call createItem and deleteItem inside of handleSubmit and handleDelete, respectively.

handleSubmit = event => {
  // console.log(this.state.item);
  this.setState({ item: "" });
  if (this.state.item !== "") {
    // add the item to the store
    this.props.createItem(this.state.item);
  }
  event.preventDefault();
};

handleDelete = event => {
  // delete the item from the store
  this.props.deleteItem(event.target.value);
};

Conclusion

And that’s it! Did this work for you? Please leave any questions and comments below!

Thank you for reading!

If you found this article helpful, please like it!

Deploy code to production now. Release to users when ready. Learn how to separate code deployment from user-facing feature releases with LaunchDarkly.

Topics:
redux ,web dev ,tutorial ,react.js ,web application development

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}