Reduce, Reuse, Redux

An intro to Redux (mostly without React)

http://codepen.io/collection/DYWRkW/

https://slides.com/justindragos/redux/live#/

 

Justin Dragos @EllisandePoet

Problem

http://codepen.io/ellisande/pen/amJYVw

Solution

Blame Moment

Moment is Stupid

  • I can't believe they did that
  • This is deeply unfair to me
  • I'm quitting open source forever
  • 183902332 + 64000 = tomorrow?

Disclaimer: I love Moment

Disclaimer: I love Moment

Problem

http://codepen.io/ellisande/pen/ZpZxrL

Solution

Blame JavaScript

Stupid Arrays

  • Legacy code is awful
  • Probably written in a weekend
  • {theRight: 'way'}

Disclaimer: I don't hate JS Arrays that much

Disclaimer: I love JavaScript

Problem

http://codepen.io/ellisande/pen/VKbwjr

Solution

We Need a Library!

Hard Problems

  • Mutable State
  • Race conditions
  • Listening for state change
  • Interface for state change

Redux to the Rescue!

It can help with:

  • None of it
  • Nadda
  • Zilch
  • Well Maybe...

What is Redux?

State Manager

  • Defines How Data Flows
  • Creates a Single Source of Truth
  • Creates a Single Source of Change
  • Forces a Discretely Testable Mutation Functions

Background

  • Created by Dan Abramov
  • Originally an Experiment in Time Travel
  • No Initial Connection with React
  • 23k Stars on Github
  • 7M Downloads on NPM

Redux Flow

Action

Reducer

New State

Dispatch

Store

Subscribe

Action

  • Fully Serializable Object
  • Must have a 'type' field

Action



const updateUserName = {
    type: 'UPDATE_USER_NAME',
    newName: 'Justin'
};

Action Creator


//Function that returns an action
const updateUserName = newName => {
    return {
        type: 'UPDATE_USER_NAME',
        newName
    };
};

//Create the action, then dispatch to the store
myAppStore.dispatch( updateUserName('Justin') );

Reducer

  • Pure Function
  • Does Not Mutate Current State
  • Only State Changer
  • Takes
    • Action
    • Current State
  • Returns
    • New State

Reducer



const myReducer = (currentState, action) => {

    //State can't change, just always return current
    return currentState;
}

Reducer



const myReducer = (currentState, action) => {
    //Tell the reducer how to handle appropriate actions
    if(action.type === 'UPATE_USER_NAME'){
        //The new state
        return {
            userName: action.newName
        };
    }
    //Return current state if we don't care about the action
    return currentState;
}

Reducer



const myReducer = (currentState, action) => {
    const newState = Object.assign({}, currentState);
    //Tell the reducer how to handle appropriate actions
    if(action.type === 'UPATE_USER_NAME'){
        //The new state
        newState.userName = newName;
    }
    //Will be current state if no actions matched
    return newState;
}

Reducer Immutability


//Bad because you are mutating current state
const myReducer = (fans, action) => {
    if(action.type === 'ADD_FAN'){
        fans.push(action.newFan);
    }
    return fans;
}


//Good because you are not mutating the existing array
const myReducer = (fans, action) => {
    if(action.type === 'ADD_FAN'){
        return [...fans, action.newFan];
    }
    return fans;
}

Store

  • Current State
  • Reducers
  • Subscriptions
  • Middleware

Store Methods

//Dispatch an action to the store
myAppStore.dispatch( myAction );

//Get current state
myAppStore.getState();

//Create the store (one time)
const myAppStore = 
    redux.createStore( reducer, initialState, middleware );

//Listener is called when state changes
myAppStore.subscribe( listener );

Problem Part Redux

http://codepen.io/ellisande/pen/amJYVw

Choose

  • Patterns
  • Middleware
  • React
  • Time Travel
  • Multiple Stores

Patterns

Combine Reducers



const myReducer = Redux.combineReducers({
    //Reducer for *just* the userName part of state
    userName: (currentName, action) => {
        //Only get passed the old userName
        if(action.type === 'NEW_USER'){
            //I just return the new userName
            return action.userName;
        }
        //Just return the new user name
        return currentName;
});

Combine Reducers

Large Reducer:

http://codepen.io/ellisande/pen/pEWxOw

Smaller Reducer:

http://codepen.io/ellisande/pen/ozGaPm

Sharing Types

http://codepen.io/ellisande/pen/zKEmya?editors=0011

Middleware

Good Uses

  • Logging
  • Async actions
  • Validation
  • Unwrap Functions

Middleware



const logger = store => next => action => {
    //Your chance to do something before the action is processed
    const updatedAction = next(action);
    //Your chance to do something after the action is processed
    return updatedAction;
}

React

React-Redux

  • Exposes a Higher Order Component (HOC)
  • State Comes in as Props
  • Can Transform State on the Way in

React Flow

Action

Reducer

New State

Dispatch

Store

Subscribe

Props

Component

Events

React Redux

import {connect} from 'react-redux';

class ShowMe {
    render(){
        return (<div>Hello from {this.props.userName}!</div>);
    }    
};

export default connect(i=>i)(ShowMe);

/*
    state structure:
    {
        userName: 'Justin'
    }
*/

React-Redux

http://codepen.io/ellisande/pen/WGkYwE

Time Travel

Time Travel Example

https://github.com/Ellisande/time-travel

Multiple Stores

Syncing Stores

UI

UI

Store

Sever

Store 1

Store 2

Store 3

Store 4

Action

Action

Questions?

  • @EllisandePoet
  • Redux: http://redux.js.org/
  • Slides:
    • https://slides.com/justindragos/redux
  • Pens:
    • http://codepen.io/collection/DYWRkW/
  • Time Travel
    • https://github.com/Ellisande/time-travel
Made with Slides.com