Modern Javascript

React + Redux

Agenda

To explain tools to use for developing a robust, performant and maintainable web application.

Pavithra Kodmad

@pkodmad

Evolution of Front end practices.

MVC

  • Controller/View/Service
  • Broadcast/Emit
  • Model structures

Modern Javascript

  • React View
  • Redux for maintaining state
  • Bundling with Webpack

React.js

  • Open sourced by Facebook
  • Built/Maintained by the community

Features

  • UI Declarative Framework
  • Virtual DOM
  • Component Structure
  • Data down approach

Declarative

How vs What?

//Imperative

var sum = 0;
for(var i=0;i< 5; i++){
    sum +=i;
}
return sum;

//Declarative

[0,1,2,3,4].reduce(function(cur, agg){
    agg += cur;
    return agg;
}, 0)

Components

  • Has a Lifecycle
  • Renders itself (JSX)
  • Receives props
  • Maintains state
export const MyComponent = React.createClass({
    render: function(){
        var props = this.props
        return <div>My Component {props.myprop}</div>
    },
    componentWillMount: function(){
        //Before mount
    },
    componentWillUnMount: function(){
        //Before unmount
    },
    ...
})

<MyComponent myprop={someprops}></MyComponent>
Initial Render
===============

getDefaultProps()
getInitialState()
componentWillMount()
render()
componentDidMount()




Props change
===============

componentWillReceiveProps()
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()




State change
===============

shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate()




Unmount
===============

componentWillUnmount()




Virtual DOM

React class vs element

Data Down approach

  • Two way data binding sucks
  • Manage state declaratively

To scale

var User = React.createClass({
    render(){
        return <div>
            <UserPicture url={this.props.url}></UserPicture>
            <UserTag details={this.props.details}></UserTag>
        </div>
    }
})

var UserPicture = React.createClass({
    render(){
        return <img src={this.props.url}></img>
    }
})

Flux

Lets Flux

Cons of Flux implementations

  • State composition was hard
  • Event emitter to multiple stores not maintainable

Redux

Change from Flux

  • No event emitter
  • Single state container
  • Recommends Immutable state

State Container

var state = {
    orderList:[],
    incidentList:[],
    selectedOrder:null
}

Reducer(No mutation)

(state, action) => newState


function counter(state, action){
    ...
    return newState
}


appState = {
    past:[{s1, a1}, {s2,a2}, {s3,a3}]
    current: {s4,a4},
    future:[]
}

Actions

var actionObject = {
    type:'ACTION_TYPE',
    data:dataToChange
}

dispatch(actionObject)

onClick(){
    var clickAction = {
        type:'CLICK_ACTION',
        data:'clicked'
    }
    dispatch(clickAction)
}

Store

var store = {
    state<priv>: <state container>,
    getState: return state,
    subscribe: <subscribe to state change .returns unsubscribe function>,
    dispatch: <dispatch actions>,
    reducer<priv>: <root reducer>
}

import {createStore} from 'redux'
//ES6 imports

createStore(reducer, initialState)

import {createStore} from 'redux';

function counter(state = 0, action){
    if(action.type === 'INCREMENT'){
        return state + 1;
    } else if(action.type === 'DECREMENT'){
        return state - 1;
    } else {
        return state;
    }
}

var store = createStore(state, initialState)

var nextcounter = counter(0, {type:'INCREMENT'});
//nextcounter = 1;
nextCounter = counter(nextCounter, {type:'INCREMENT'});
//nextCounter = 2;
nextCounter = counter(nextCounter, {type:'somethingelse'});
//nextCounter = 2;
nextCounter = counter(nextCounter, {type:'DECREMENT'});
//nextCounter = 1;


import {createStore} from 'redux';

function counter(state = 0, action){
    if(action.type === 'INCREMENT'){
        return state + 1;
    } else if(action.type === 'DECREMENT'){
        return state - 1;
    } else {
        return state;
    }
}

var store = createStore(counter, initialState)

function render(){
    ReactDOM.render(<Counter counter={store.getState()} dispatch={store.dispatch}/>, document.getElementById('root'))
}

store.subscribe(render())

var Counter = React.createClass({
    render: function(){
        var {counter, dispatch} = this.props;
        <div>
            <div>
                {counter}
            </div>
            <button onClick={dispatch({type:'INCREMENT'})}>INCREMENT</button>
            <button onClick={dispatch({type:'DECREMENT'})}>DECREMENT</button>
        </div>
    }
})

Using redux

 

  • react-redux
  • ngRedux
  • backbone-redux
  • ember-redux

react-redux

import {createStore, combineReducers} from 'redux'
import {Provider} from 'react-redux'

import {reducer1, reducer2} from  '../reducers'
import App from '../App'

var rootReducer = combineReducers(reducer1, reducer2);
var store = createStore(rootReducer,{});


<Provider store='store'>
    <App/>
</Provider>

//uses React context


//App.js

import {connect} from 'react-redux'

import appAction from '../appAction'

var App = React.createClass({
    render(){
        return <div>This is the app showing {this.props.filteredState}</div>
    }
})

function mapStateToProps(state){
    return filteredState; //{substate1, substate2}
}

export default connect(mapStateToProps, {appAction})(App)




When to Redux?

  • Deep parent child relationships
  • Sibling components trying to communicate 
  • Aggregator components like Notifications

Learn Redux

M

By Pavithra Kodmad

M

  • 1,212