more on that in just a sec
JavaScript does (browser, server, native)
though often found with React
I'm totally plagiarizing rn
at ~ 2kB
not managed by redux
SELECT * FROM `player`
WHERE `name` LIKE 'Jared A%'
not managed by redux
HTTP/1.0 200 OK
Set-Cookie: LSID=DQAAAK…Eaem_vYg; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly
Set-Cookie: HSID=AYQEVn….DKrdst; Domain=.foo.com; Path=/; Expires=Wed, 13 Jan 2021 22:23:01 GMT; HttpOnly
Set-Cookie: SSID=Ap4P….GTEq; Domain=foo.com; Path=/; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly
not managed by redux
like :hover or :active state
const scores = {
Jared: Infinity,
Bruce: 1,
Matt: NaN
};
not app state
is app state
example
may consist of:
If a model can update another model, then a view can update a model, which updates another model, and this, in turn, might cause another view to update. At some point, you no longer understand what happens in your app as you have lost control over the when, why, and how of its state. When a system is opaque and non-deterministic, it’s hard to reproduce bugs or add new features.
http://redux.js.org/docs/introduction/Motivation.html
stuff is happening and you can't even
the same set of actions produce different results
Insanity: doing the same thing over and over again and expecting different results.
and not in the good way
When application state is decentralized and spread across your entire app - often hidden with behaviors, in functions, in closures, and/or bunch of global objects - it becomes even more impossible to manage as your app scales
class ScoreCard {
constructor(name, initialScore=0) {
this.name = name;
this.score = initialScore;
}
add(number) {
this.score += number;
}
}
of Redux
http://redux.js.org/docs/introduction/ThreePrinciples.html
The state of your whole application is stored in an object tree within a single store.
The only way to mutate the state is to emit an action, an object describing what happened.
emitted actions (along with the current state) are passed to pure functions which return a new state
Redux has a
import {createStore} from 'redux';
// you import your reducers
// you spend most of your time writing reducers
// more on that in a minute...
import myReducer from './my/reducer.js';
// you create the redux store from reducer(s)
export const store = createStore(myReducer);
// you get current state at any time by...
store.getState();
// you subscribe to be notified when things change
store.subscribe( () =>
console.log(store.getState())
);
// dispatch "actions" asking store to change state...
// actions are just POJOS with a `type` and optional data
store.dispatch({type: "INCREMENT"});
(previousState, action) => newState
Things you should never do inside a reducer:
export default (state = 0, {type}) => {
switch(type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
Did we:
{type}
redux internal state tree
{type}
(state,action)
=> newState
reducer
import {createStore} from 'redux';
const myReducer = (state = 0, {type}) => {
switch(type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
const store = createStore(myReducer);
store.subscribe( () =>
console.log(store.getState())
);
store.dispatch({type: "INCREMENT"});
store.dispatch({type: "DECREMENT"});
Actions
const action = { type: 'ADD', number: 10 };
dispatch(action);
Action Creators
const add = (number) =>
({ type: 'ADD', number });
dispatch( add(10) );
don't write these
write these
add 10...
divide 2...
multiply 5...
multiply 4...
divide 10...
minus 1...
divide 3...
...what do we have?
start 0...
/* Task #1 */
const roadTripDad =
(state = 0, {type, number}) => {
switch(type) {
case 'START':
return number;
case 'ADD':
return state + number;
case 'SUBTRACT':
return state - number;
case 'MULTIPLY':
return state * number;
case 'DIVIDE':
return state / number;
default:
return state;
}
}
/* Task #2 */
const start = number =>
({type: 'START', number});
const add = number =>
({type: 'ADD', number});
const subtract = number =>
({type: 'SUBTRACT', number});
const multiply = number =>
({type: 'MULTIPLY', number});
const divide = number =>
({type: 'DIVIDE', number});
/* Task #3 */
const store = createStore(roadTripDad);
store.subscribe(() => {
render(
store.getState(),
number =>
store.dispatch(add(number)),
number =>
store.dispatch(subtract(number)),
number =>
store.dispatch(multiply(number)),
number =>
store.dispatch(divide(number))
)
});
/* Task #4 */
store.dispatch(start(10))
// import createStore AND combineReducers
import {createStore, combineReducers} from 'redux';
// import all your apps' reducers
import talks from '../reducers/talks.js';
import speakers from '../reducers/speakers.js';
import sessions from '../reducers/sessions.js';
// create the state tree (aka: root reducer)
const rootReducer = combineReducers({talks, speakers, sessions});
// create the redux store from reducer(s)
export const store = createStore(rootReducer);
console.log( store.getState() );
/* {talks: ..., speakers: ..., sessions: ...}; */
Combine Reducers
{type}
redux internal state tree
{type}
(state,action)
=> newState
(state,action)
=> newState
{type}
reducer
reducer
things you should never do inside a reducer
{type}
redux internal state tree
{type}
(state,action)
=> newState
()=>{}
middleware
reducer
import { createStore, combineReducers, applyMiddleware } from 'redux';
import reducers from '../path/to/reducers.js';
// middleware that lets you dispatch thunks
import thunk from 'redux-thunk';
const rootReducer = combineReducers(reducers);
export const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
// Meet thunks.
// A thunk is a function that returns a function.
// This is a thunk.
function makeASandwichWithSecretSauce(forPerson) {
// Invert control!
// Return a function that accepts `dispatch` so we can dispatch later.
// Thunk middleware knows how to turn thunk async actions into actions.
return function (dispatch) {
return fetchSecretSauce().then(
sauce => dispatch(makeASandwich(forPerson, sauce)),
error => dispatch(apologize('The Sandwich Shop', forPerson, error))
);
};
}
store.dispatch(
makeASandwichWithSecretSauce('My wife')
)