Redux 101

State Management in React

@zpnk

@wedgies

What Is Redux?

WHY is redux a good idea?

How can I use redux?

What is Redux?

  • A State Management Library

  • A PHIlosophy For Building JS Apps

  • An Ecosystem of Tools and Patterns

source: youhavetolearncomputers.com

source: youhavetolearncomputers.com

source: youhavetolearncomputers.com

A Library...

Predictable State container for JS APPs

 

  • Consistent Behavior

  • Testable

  • View Independent

A Philosophy...

The Three Principles of Redux:

 

  • Single Source of Truth

  • State is Read-only

  • Purely Functional Changes

AN Ecosystem...

A Careful API leads to Extensibility

 

  • Tiny Core Library (2kb)

  • Based on Flux, ELm, EtC

  • 2700+ Related npm Packages  

Why is Redux A good idea?

Apps are Complicated

  • Server Respones, locally Created Data

  • UI State (Spinners, Alerts, Errors

  • Optimistic Updates, Server-Side Rendering...

React is The "V" in "MVC"

  • Complex Component state is a bad Idea

  • Component Logic Grows 

  • Internal State Flow is hard to trace

You want to...

  • test your Code

  • Document Your Code

  • Understand your code

How Can I use Redux?

// Action Creators
const incrementCounter = () => ({
  type: 'INCREMENT'
})

const decrementCounter = () => ({
  type: 'DECREMENT'
})


// Reducer
const counter = (state = 0, action) => {
  switch(action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }
}

// Store
import {createStore} from 'redux'

const store = createStore(counter)


// Dispatch actions
store.dispatch(incrementCounter())

// Listen for changes
store.subscribe(render)

// Get the current state
const state = store.getState()

Redux Basics

import React from 'react'
import {render} from 'react-dom'
import {Provider} from 'react-redux'
import {createStore} from 'redux'
import counterReducer from './reducers'
import Counter from './containers/Counter'

const store = createStore(counterReducer)

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

import React from 'react'
import {connect} from 'react-redux'
import {incrementCounter, decrementCounter} from '../actions'

const Counter = ({count, incrementCounter, decrementCounter}) => (
  <div>
    <h1>{count}</h1>
    <button onClick={incrementCounter}>+</button>
    <button onClick={decrementCounter}>-</button>
  </div>
)

const mapStateToProps = ({count}) => ({count})
const mapDispatchToProps = {incrementCounter, decrementCounter}

export default connect(mapStateToProps, mapDispatchToProps)(Counter)

containers/Counter.js

index.js

React-redux

// store/index.js
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './reducers/index'

const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
)

export default store

// actions/index.js
export const fetchSecretSauce = () => fetch('https://www.google.com/search?q=secret+sauce')
}
// middleware/api.js
export const CALL_API = 'Call_API'

export default store => next => action => {
  const callApi = action[CALL_API]
  if (typeof callApi === 'undefined') return next(action)

  const {types, endpoint} = callApi
  const [requestType, successType, failureType] = types

  next({type: requestType})

  fetch(endpoint)
  .then(res => { return next({type: successType, res}) })
  .catch(res => { return next({type: failureType, msg: 'Request failed}) })
}

Custom Middleware

Redux-thunk

Async

// actions/index.js
export const loadQuestion = (id) => ({
  [CALL_API]: {
    types: [
      QUESTION_LOAD_REQUEST,
      QUESTION_LOAD_SUCCESS,
      QUESTION_LOAD_FAILURE
    ],
    endpoint: `/api/question/${id}`
  }
})

Resources

redux.js.org (!!!)

 

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

 

github.com/xgrommx/awesome-redux

 

@dan_abramov

Questions?

Made with Slides.com