React 6

React Redux

What is Redux?

Redux is an open source, state management library.

 

Redux was created by Dan Abramov, who also helped build create-react-app.

 

You can learn Redux directly from Dan here:

https://egghead.io/courses/getting-started-with-redux

 

Redux is a tool that allows us to manage an application's state in a more convenient way than needing to pass down/up through props. 

What is Redux?

Redux Dataflow

What is React Redux?

The Redux pattern isn't exclusive to React.
 

There is a, however, a React Redux package that makes implementing Redux into React easier.

 

React Redux makes the Redux pattern even more useful by making the Store state available on props.

 

We'll be learning to use the Redux pattern with React Redux. 

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 their own state, as well as action creator functions, and a reducer function that will work together to change the application 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});
        // return {...state, {user: action.payload}}
        default:
            return state;
    };
};

initial state values

action creator function

reducer function

Action Creators

Action creators are functions that allow changes to the redux state.

 

They return an action object with two properties: a type and a payload.

 

The type is used in the reducer's switch statement, and the payload contains the new values to assign 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 returned from an action creator is used as the case for the switch, to determine how state should change.

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 the place where we keep the application's state.

 

The store is a place other components can connect to in order to receive updates about information they might need.

 

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 enable access to the store, we first need to wrap a Provider component 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 pass information from our store state to any component that needs it by using a connect function, and a mapStateToProps function.

 

These two functions will work together to populate the props object of the component with information from the store state. This process is known as subscribing.

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 the redux store state available to the props object

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 creator

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 enables  asynchronous code to work inside of redux.

 

This means we can make axios calls to a server from within redux.

 

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

Now that the setup is complete, we can make asynchronous code work in our action creators:

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

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

Note: 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;
    };
};

React-promise-middleware will append a promise-related status to any asynchronous actions that are fired from within redux.

Using Multiple Reducers

When using multiple reducers, we need to 'bundle' them to make each of their states available on the store state.

 

We can do this using the combineReducers method that comes with the redux package.

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

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

export default createStore(rootReducer);

Copy of React 6

By Cole Finlayson

Copy of React 6

React Redux

  • 146