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?
Redux 101
By zpnk
Redux 101
Intro to Redux presentation for VegasJS #52 - 7/19/16
- 1,739