Redux是用来管理程序状态的工具,它提供了一些高阶函数让功能越来越丰富。
1. 用reducer根据action对state进行变换:
reducer(state,action)
// type Action = {Type, Value}
// type ActionCreator = Value -> Action
// actionCreator :: ActionCreator
const actionCreator = v => ({
type: 'ADD1',
v
})
// type Reducer = (State, Action) -> State
// reducer :: Reducer
const reducer = (state, action) => {
switch (action.type) {
case 'ADD1':
return state + 1
default:
return state
}
}
// testcase
const initialState = 1
const action = actionCreator(initialState)
const state = reducer(initialState, action)
console.assert(state === 2)
2. 用store保存state,store处理action之后改变状态:
store.dispatch(action)
// type Action = {Type, Value}
// type ActionCreator = Value -> Action
// actionCreator :: ActionCreator
const actionCreator = v => ({
type: 'ADD1',
v
})
// type Reducer = (State, Action) -> State
// reducer :: Reducer
const reducer = (state, action) => {
switch (action.type) {
case 'ADD1':
return state + 1
default:
return state
}
}
// type Listener = (State, Action) -> ()
// type GetState = () -> State
// type Subscribe = Listener -> ()
// type Dispatch = Action -> ()
// type Store = {GetState, Subscribe, Dispatch}
// type CreateStore = (Reducer, State) -> Store
// createStore :: CreateStore
const createStore = (reducer, initialState) => {
let state = initialState,
listenerList = []
return {
getState: () => state,
subscribe: listener => {
listenerList.push(listener)
},
dispatch: action => {
listenerList.forEach(listener => listener(state, action))
state = reducer(state, action)
}
}
}
// testcase
const initialState = 1
const store = createStore(reducer, initialState)
console.assert(store.getState() === 1)
const action = actionCreator(initialState)
const listener = (state, action) => {
console.assert(state === 1)
console.assert(action.type === 'ADD1')
}
store.subscribe(listener)
store.dispatch(action)
console.assert(store.getState() === 2)
3. 用bindActionCreator得到可根据当前state直接修改store的sideEffectAction:
sideEffectAction(initialState)
// type Action = {Type, Value}
// type ActionCreator = Value -> Action
// actionCreator :: ActionCreator
const actionCreator = v => ({
type: 'ADD1',
v
})
// type Reducer = (State, Action) -> State
// reducer :: Reducer
const reducer = (state, action) => {
switch (action.type) {
case 'ADD1':
return state + 1
default:
return state
}
}
// type Listener = (State, Action) -> ()
// type GetState = () -> State
// type Subscribe = Listener -> ()
// type Dispatch = Action -> ()
// type Store = {GetState, Subscribe, Dispatch}
// type CreateStore = (Reducer, State) -> Store
// createStore :: CreateStore
const createStore = (reducer, initialState) => {
let state = initialState,
listenerList = []
return {
getState: () => state,
subscribe: listener => {
listenerList.push(listener)
},
dispatch: action => {
listenerList.forEach(listener => listener(state, action))
state = reducer(state, action)
}
}
}
// bindActionCreator :: (ActionCreator, Dispatch) -> State -> ()
const bindActionCreator = (actionCreator, dispatch) => initialState => dispatch(actionCreator(initialState))
// testcase
const initialState = 1
const store = createStore(reducer, initialState)
const sideEffectAction = bindActionCreator(actionCreator, store.dispatch)
sideEffectAction(initialState)
console.assert(store.getState() === 2)
4. 用applyMiddleware加强createStore,提高store处理action的能力:
storeWithMiddleware.dispatch(action)
// type Action = {Type, Value}
// type ActionCreator = Value -> Action
// actionCreator :: ActionCreator
const actionCreator = v => ({
type: 'ADD1',
v
})
// type Reducer = (State, Action) -> State
// reducer :: Reducer
const reducer = (state, action) => {
switch (action.type) {
case 'ADD1':
return state + 1
default:
return state
}
}
// type Listener = (State, Action) -> ()
// type GetState = () -> State
// type Subscribe = Listener -> ()
// type Dispatch = Action -> ()
// type Store = {GetState, Subscribe, Dispatch}
// type CreateStore = (Reducer, State) -> Store
// createStore :: CreateStore
const createStore = (reducer, initialState) => {
let state = initialState,
listenerList = []
return {
getState: () => state,
subscribe: listener => {
listenerList.push(listener)
},
dispatch: action => {
listenerList.forEach(listener => listener(state, action))
state = reducer(state, action)
}
}
}
// compose :: [t -> t] -> (t -> t)
const compose = (...fns) => {
let last = fns.pop()
return (...args) => fns.reduceRight((memo, fn) => fn(memo), last(...args))
}
// type Next = Dispatch
// type Middleware = {GetState, Dispatch} -> Next -> Dispatch
// middleware :: Middleware
const middleware = ({ getState, dispatch }) => next => action => {
// for example:
return next(action)
}
// applyMiddleware :: [Middleware] -> CreateStore -> CreateStore
const applyMiddleware = (...middlewares) => createStore => (reducer, initialState) => {
let store = createStore(reducer, initialState),
dispatch = store.dispatch,
// chain :: [Next -> Dispatch]
chain = middlewares.map(middleware => middleware({
getState: store.getState,
dispatch: action => dispatch(action)
}))
dispatch = compose(...chain)(dispatch)
return {
getState: store.getState,
subscribe: store.subscribe,
dispatch
}
}
// testcase
const initialState = 1
const createStoreWithMiddleware = applyMiddleware(middleware)(createStore)
const store = createStoreWithMiddleware(reducer, initialState)
const action = actionCreator(initialState)
const listener = (state, action) => {
console.assert(state === 1)
console.assert(action.type === 'ADD1')
}
store.subscribe(listener)
store.dispatch(action)
console.assert(store.getState() === 2)