App
├── Header
│ └── h1
└── List
└── ul
├── li
├── li
└── li
this.state
this.setState({
keyInStateToMerge: newValue
})
this.props
class App extends React.Component {
constructor(...args) {
super(...args);
this.handleIncrease = this.handleIncrease.bind(this);
this.state = { count: 0 }
}
handleIncrease() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<h1>Count is {this.state.count}</h1>
<Counter onIncrease={this.handleIncrease} />
</div>
)
} }
<button onClick={doCoolStuff}>
Do Cool Stuff
</button>
import React, { Component, PropTypes } from 'react'
class App extends Component {
static propTypes = {
sum: PropTypes.number
}
}
You have some calculator view, it produces array of strings with either 'Inc' or 'Dec'.
Build function to get total result if you started with 0.
const initialSum = 0;
const operations = ['inc', 'dec', 'whatever', 'dec'];
const sum = operations.reduce((currentSum, opType) => {
if (opType === 'inc') {
return currentSum + 1
}
if (opType === 'dec') {
return currentSum - 1;
}
return currentSum;
}, initialSum)
console.log(sum); // - 1
const initialState = 0;
const actions = [
{type: 'inc'}, {type: 'dec'},
{type: 'whatever', {type: 'dec'}];
const store = actions.reduce((currentSum, {type}) => {
if (type === 'inc') {
return currentSum + 1
}
if (type === 'dec') {
return currentSum - 1;
}
return currentSum;
}, initialState)
console.log(store); // - 1
const initialState = 0;
count sumReducer = (state = initialState, action) {
switch (action.type) {
case 'inc':
return state + 1
case 'dec':
return state - 1
default:
return state
}
}
const store = createStore(combineReducers({ sum: sumReducer }))
store
is object. You can subscribe
to its changesstore
state by calling store.getState()
dispatch
on store with action.store.dispatch({ type: 'inc' })
react-redux
is glue tying react + redux store<Provider store={store}><YourApp /></Provider>
wrapperconst mapStateToProps = (state) => ({
sum: state.sum,
});
class App extends React.component {
// some binding in constructor left behind
increase() { this.props.dispatch({ type: 'inc' }) }
decrease() { this.props.dispatch({ type: 'dec' }) }
render() {
const btn = (text, cb) => <button onClick={cb}>{text}</button>;
return (
<div>Sum: {this.props.sum}
{btn(this.increase, '+')}{btn(this.decrease, '-')}
</div>
)
}
}
export default connect(mapStateToProps)(App)
export const DEC_CONST = 'dec';
export const decrease = () => ({
type: DEC_CONST
})
const DEC_CONST = 'dec';
export default const sumReducer = (initialState, action) => {
/* handle DEC_CONST here */
}
export const decrease = () => ({
type: DEC_CONST
});
{
type: /* … */
payload: {
/* … */
}
error: {
/* … */
}
}
// utils/redux
export function createAction(type, payloadCreator) {
return (...args) => {
const action = { type };
if (typeof payloadCreator === 'function') {
action.payload = payloadCreator(...args);
}
return action;
};
}
// in module
export const decreaseBy = createAction(
DEC_CONST, (amount) => ({ data: amount })
)
decreaseBy(15)
/* {"type":"dec","payload":{"data":14}} */
// utils/redux
export function createReducer(initialState, reducerMap) {
return (state = initialState, action = {}) => {
const reducer = reducerMap[action.type];
return reducer ? { ...state, ...reducer(state, action.payload) } : state;
};
}
// in module
export default sumReducer = createReducer(initialState, {
[DEC_CONST]: state => state - 1,
[INC_CONST]: state => state + 1
})
function fetchThing(byId) {
return dispatch => {
dispatch(loading())
requestThing(byId)
.then((thing) => dispatch(receive(thing)))
.catch((error) => dispatch(failure(thing)))
};
}
const createConstants = (prefix) => ({
loading: `${prefix}/loading`,
receive: `${prefix}/receive`,
failure: `${prefix}/failure`,
})
const createActions = (prefix) => {
const { loading, receive, failure } = createConstants(prefix);
return {
loading: createAction(loading)
receive: createAction(receive, (item) => ({ item }))
failure: createAction(failure, (error) => ({ error }))
}
}
export const createFecthingItemReducer = (prefix) => {
const { loading, receive, failure } = createConstants(prefix);
return {
[loading]: () => ({ isLoading: true, item: null, error: null }),
[receive]: ({item}) => ({ isLoading: true, item, error: null }),
[failure]: ({error}) => ({ isLoading: true, item: null, error }),
}
}
export const createFetcher = (prefix) => {
const { loading, receive, failure } = createActions(prefix);
(byId) =>
dispatch => {
dispatch(loading())
requestThing(byId)
.then((thing) => dispatch(receive(thing)))
.catch((error) => dispatch(failure(thing)))
} }
const prefix = 'Book'
export default reducer = (initialState, {
...createFecthingItemReducer(prefix)
[MY_ACTIONS]: () => ({ /* … */})
})
export fetchBook = createFetcher(prefix);
import React, { Component, PropTypes as toBe } from 'react'
class App extends Component {
static propTypes = {
sum: toBe.number
}
}
import { Component } from 'components'