React from scratch Part 3
Tags: react, redux, javascript, beginners
Published: 2020-08-31 08:13:46

In the third and final part of the series "React from scratch" we will implement a statemanagement by adding Redux to our application.
## Prerequisites
Part 3 will start where we left off in part 2. If you didn't already, go ahead and finish [part 1](https://dev.to/jakobkit/react-from-scratch-part-1-3lmn) and [part 2](https://dev.to/jakobkit/react-from-scratch-part-2-1ap1) or just [clone part 2](https://github.com/JakobKIT/getting-started-react)  from my repo and start from there.

## New dependencies
Let's get started by adding redux and some more new dependencies to our project.
```Shell
$ npm i redux react-redux redux-thunk
```
- ***[redux](https://redux.js.org/):*** A javascript library for state containers.
- ***[react-redux](https://www.npmjs.com/package/react-redux):*** React bindings for redux.
- ***[redux-thunk](https://www.npmjs.com/package/redux-thunk):*** Thunk middleware for redux.

If you want to know more about *thunk* I recommend reading [this](https://stackoverflow.com/questions/35411423/how-to-dispatch-a-redux-action-with-a-timeout/35415559#35415559).

## Global Store
Our goal is to create a, so called, store which holds all the post data of our application.
This store will also provide access to methods for handling with the store data, e.g. adding or removing posts from the store.
After we created that store we want to get rid of the state inside our *Todo-Component*.

So first let's start with creating new folders:
```Shell
$ mkdir store
$ mkdir actions
$ mkdir reducers
```
Next up we will create a new file inside the store folder:
```Shell
$ cd store/
$ touch configureStore.js
```
This file will contain all the configuration of our global store, such as adding the thunk middleware.
The content should look like this:
```JavaScript
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers';

const initialState = {};

const middleware = [thunk];

const store = createStore(
  rootReducer,
  initialState,
  compose(
    applyMiddleware(...middleware),
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
  )
);

export default store;
```
With the *createStore* method we can create a **Redux Store**. This store needs a *reducer*, the initial state of the application and the so called enhancers.
The enhancers are middleware that add functionality to our store. In our case we enable the [Redux Developer Tools](https://github.com/zalmoxisus/redux-devtools-extension) and added *redux-thunk*.

Now we need to pass this store to our application. This is done by using a *Provider* from the *react-redux* library we installed earlier.
We need to provide the store to our main component. So let's open up our *Root.js* and implement it:
```JSX
import React from 'react';
import Routes from '../Routes';
import { Provider } from 'react-redux';

const Root = ({ store }) => (
    <Provider store={store}>
        <Routes />
    </Provider>
);

export default Root;
```
Our **Root Component** can accept the store now, we just need to pass it in. We do this in our *index.js* file:
```JSX
import React, { StrictMode } from 'react';
import ReactDOM from 'react-dom';
import store from './store/configureStore';
import Root from './containers/Root';
import './index.scss';

ReactDOM.render(
  <StrictMode>
    <Root store={store} />
  </StrictMode>,
  document.querySelector('#root'),
);
```

## Reducers

For this code to work we need to create the rootReducer next:
```Shell
$ cd ../reducers/
$ touch index.js
$ touch todoReducer.js
```
Let's open the *index.js* and add the following:
```JavaScript
import { combineReducers } from 'redux';
import todoReducer from './todoReducer';

export default combineReducers({
  todo: todoReducer,
});
```
The method *combineReducers* takes an object with all the reducers of your application.
From that it creates a single reducer which we can pass to our store, like we did in the *configureStore.js*.
Now we switch into the *todoReducer* to give it some life!
```JavaScript
import { ADD_TODO, DELETE_TODO } from '../actions/types';
const initialState = {
  todos: localStorage.getItem('todos') ? 
    JSON.parse(localStorage.getItem('todos')) : [],
  error: null,
}

export default (state = initialState, action) => {
  switch (action.type) {
    case ADD_TODO:
      const newTodos = [action.payload, ...state.todos]
      localStorage.setItem('todos', JSON.stringify(newTodos))
      return {
        ...state,
        todos: newTodos,
      };
    case DELETE_TODO:
      return {
        ...state,
        todos: state.todos.filter(todo => todo._id !== action.payload)
      };
  
    default:
      return state;
  }
}
```
The reducer has the initial state for all the todos. We store all the todos in the [localStorage](https://javascript.info/localstorage) of the browser.
We do that, so we can still have access to our todos after reloading the page.
The switch case creates a new state depending on the action called and the current state.
It does not modify the current state because **redux** implements the concept of immutability.

## Actions

Next up we create the actions that the reducer listens to.
```Shell
$ cd ../actions/
$ touch types.js
$ touch todoActions.js
```
First of we create the constants in *types.js*, that we already used in our *todoReducer*.
```JavaScript
export const ADD_TODO = 'ADD_TODO';
export const DELETE_TODO = 'DELETE_TODO';
```
Now we start implementing our two actions **ADD** and **DELETE** in *todoActions.js*:
```JavaScript
import { ADD_TODO, DELETE_TODO } from './types';

export const addTodo = (todo) => (dispatch) => {
  dispatch({
    type: ADD_TODO,
    payload: todo,
  });
};
```
If we would store our todos in some kind of backend we could send it there via *axios.js* or some other framework.
But for now we just dispatch the **todo** we pass in and the type **ADD_TODO** to our **todoReducer**.
Right below the *addTodo* we implement the *deleteTodo* like that:
```JavaScript
export const deleteTodo = (id) => (dispatch) => {
  dispatch({
    type: DELETE_TODO,
    payload: id,
  })
};
```
It works nearly the same as the **addTodo** action, except we don't pass in the whole **todo**.
We just pass in the **id** of the **todo** we want to delete.

## Connect Redux with React

At this point in time, our **Todo App** still works the same as before. To utilize the **Redux Store** we need to connect it to our *Todo component*.

```JSX
import React, { Component, Fragment } from 'react'
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { addTodo, deleteTodo } from '../actions/todoActions';
import TodoListContainer from '../containers/TodoList';
import NewTodoContainer from '../containers/NewTodo';

export class Todo extends Component {

  constructor(props) {
    super(props);
    this.state = {
      showNewTodo: false,
      title: '',
      text: '',
    };
  }

  static propTypes = {
    todos: PropTypes.array.isRequired,
    addTodo: PropTypes.func.isRequired,
    deleteTodo: PropTypes.func.isRequired,
  };

  toggleNewTodo() {
    this.setState({
      showNewTodo: !this.state.showNewTodo
    });
  }

  onChange(event) {
    this.setState({ [event.target.name]: event.target.value });
  }

  onSubmit(event) {
    event.preventDefault();
    const { text, title } = this.state;
    const newTodo = { id: this.props.todos.length + 1, title, text };
    this.props.addTodo(newTodo);
    this.setState({
      showNewTodo: false,
      title: '',
      text: '',
    });
  }

  render() {
    const { showNewTodo } = this.state;
    return (
      <Fragment>
        <div className="container-fluid">
          <div className="col w-25 mt-4 mx-auto">
            { showNewTodo ? 
              (<Fragment>
                <button className="mb-2 w-100 btn btn-danger" onClick={this.toggleNewTodo.bind(this)}>Cancel</button> 
                <NewTodoContainer 
                  onChange={this.onChange.bind(this)}
                  onSubmit={this.onSubmit.bind(this)} />
              </Fragment>)
              : (<button className="mb-2 w-100 btn btn-success" onClick={this.toggleNewTodo.bind(this)}>Add Todo</button>)
              }
            <TodoListContainer 
              todos={this.props.todos}
            />
          </div>
        </div>
      </Fragment>
    );
  }
}

const mapStateToProps = (state) => ({
  todos: state.todo.todos,
});

const mapDispatchToProps = (dispatch) => ({
  addTodo(todo) {
    dispatch(addTodo(todo));
  },
  deleteTodo(id) {
    dispatch(deleteTodo(id));
  },
});


export default connect(mapStateToProps, mapDispatchToProps)(Todo);
```
There is a lot of stuff happening here at once so let's break it down from top to bottom:

1. We imported the connect function from *react-redux*. Then we imported the *PropTypes* and the two new actions we implemented before, *addTodo* and *deleteTodo*.
2. The constructor needed some cleanup so we removed all the *todos* because we keep them in our store from now on.
3.  We added static *propTypes* to ensure that the todos from the store and the two actions we imported earlier get the right types and are required for this component.
4.  In the *onSubmit* method we create a newTodo that we pass on to our *addTodo* action by accessing it via **this.props**. We did remove the todos from the *setState* method because the component-state does not contain the list of todos anymore.
5. Right below the component-class we added two arrow functions.
 **mapStateToProps** gets the redux state passed in and return our todos by adding it to **this.props** of our component.
 **mapDispatchToProps** maps our actions, *addTodo* and *deleteTodo*, to **this.props** of our component.
6.  Finally we used the *react-redux* method **connect** to map the two arrow functions to our *Todo* component, so that we can access all the state and actions via **this.props**.

## Conclusion
That's it for part 3 of this series.
We implemented a redux store, reducer and actions into our application. After we did that we connected this new feature to our Todo-component by using *react-redux*.
By doing all this we got a quick introduction to *localStorage* and can now write and read data from the browsers *localStorage*.

As you may have noticed we did not use the *deleteTodo* method anywhere. I did this on purpose so that you can add the delete functionality to this component by yourself.
I hope you enjoyed it!

If you got any question just contact me via [Twitter](https://twitter.com/JakobKIT).


All the code for this multipart series can be found in this [GitHub-Repository](https://github.com/JakobKIT/getting-started-react).