Redux/React Redux

What is Redux?

Redux was created by Dan Abramov, who also helped build create-react-app. Redux is a state management tool that allows us to manage an application state that components can subscribe to to access that state. 

What is Redux?

Redux Dataflow

What is React Redux?

Redux isn't specific to React, but there is a React Redux package that makes implementing Redux into React easier. React Redux better follows the structure of React, making the application state available as props.

Redux Setup

To set-up Redux/React Redux, we need to install the following packages:

npm install redux react-redux

Then create a redux folder inside of your src folder:

Redux Setup

Redux set-up involves two kinds of files: reducer files(can have multiple), and a store file. Reducers are where state can be stored, as well as 'actions' to change the state. The store makes the state from our reducers available to our application.

Reducers

Reducer files will hold state, as well as actions to change state. Their setup looks like the following:

const initialState = {
    user: {}
};

const LOGIN_USER = 'LOGIN_USER';

export function loginUser(user){
    return {
        type: LOGIN_USER,
        payload: user
    };
};

export default function userReducer(state = initialState, action){
    switch(action.type){
        case LOGIN_USER:
            return Object.assign({}, state, {user: action.payload});
        default:
            return state;
    };
};

state values

action builder

reducer function

Action Builders

Action builders are functions that allow changes to the redux state. They will return an object with two properties: a type and a payload. The type is used for the reducers switch statement, and the payload is generally new values to put on state.

export function loginUser(user){
    return {
        type: LOGIN_USER,
        payload: user
    };
};

Reducer Function

The reducer function contains a switch statement that helps change the state. The action type from action builders is used as the case for the switch, to determine how state is changing.

export default function userReducer(state = initialState, action){
    switch(action.type){
        case LOGIN_USER:
            return Object.assign({}, state, {user: action.payload});
            // spread operator: return {...state, user: action.payload}
        default:
            return state;
    };
};

Redux Store

The redux store is used to make state available to our application. The set up for a redux store is as follows:

import {createStore} from 'redux';
import userReducer from './reducer';

export default createStore(userReducer);

import {createStore}

import reducer file(s)

pass reducer into createStore

React Redux Setup

Now that the store and reducer are setup, we can now use React Redux to connect the store to our application. To connect with our application, we first need to wrap Provider around our application.

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

import store from './redux/store';
import {Provider} from 'react-redux';

ReactDOM.render(
<Provider store={store}>
    <App />
</Provider>
, document.getElementById('root'));

wrap App with Provider, passing in store as a prop

import store and Provider

React Redux Setup

Once Provider has been wrapped around the application, we can now connect our redux state to any component that needs it by using connect, and mapStateTo Props. This will make selected items from redux state available as props for the component. This process is known as 'subscribing'.

You right now -->

React Redux Setup

import React, { Component } from 'react'
import {connect} from 'react-redux';

class App extends Component {
  render() {
    return (
      <div>
        
      </div>
    )
  }
};

const mapStateToProps = (state) => state

export default connect(mapStateToProps)(App);

import connect

makes state available as props

pass mapStateToProps into connect

Using Actions

import React, { Component } from 'react'
import {connect} from 'react-redux';
import {actionName} from './redux/reducer';

class App extends Component {
  render() {
    return (
      <div>
        
      </div>
    )
  }
};

const mapStateToProps = (state) => state

export default connect(mapStateToProps, {actionName})(App);

import action

pass action into connect as the second argument

Note: If you aren't using redux state, but are using an action, the first argument of connect needs to be null.

Redux Promise Middleware

redux-promise-middleware is a package that allows asynchronous code inside of redux. This allows you to make requests to your server. To use it, install redux-promise-middleware from NPM:

npm install redux-promise-middleware

Then make the following changes to your store file:

// import the store and apply middleware
import {createStore, applyMiddleware} from 'redux';
import userReducer from './reducer';
// import promise middleware
import promiseMiddleware from 'redux-promise-middleware';
export default createStore(userReducer, applyMiddleware(promiseMiddleware));

Redux Promise Middleware

Once those changes have been made, you can make asynchronous code in your action builders:

export function getRandomUser(){
    const randomUser = axios.get('https://randomuser.me/api/')
    .then((res) => res.data.results[0]);

    return {
        type: GET_USER,
        payload: randomUser
    };
}

Promises have three states: Pending, Fulfilled, and Rejected. Redux-promise-middleware allows us to use these in our switch statement in the reducer function...

Redux Promise Middleware

export default function userReducer(state = initialState, action){
    switch(action.type){
        case GET_USER + '_PENDING':
            return Object.assign({}, state, {laoding: true});
        case GET_USER + '_FULFILLED':
                return Object.assign({}, state, {user: action.payload, loading: false});
        case GET_USER + '_REJECTED':
            return Object.assign({}, state, {errorMessage: action.payload});
        default:
            return state;
    };
};

Using Multiple Reducers

When using multiple reducers, we need to 'bundle' them to make all of redux state available in one place. We can do this using the 'combineReducers' method from redux.

import {createStore, combineReducers} from 'redux';
import userReducer from './reducer';
import carReducer from './carReducer'

const rootReducer = combineReducers({
    userReducer,
    carReducer
});

export default createStore(rootReducer);

Redux/React Redux

By Matthew Bodily

Redux/React Redux

  • 218