Compose(…funcs)
/**
* compose(f,h,g)(...args) => f(g(h(...args)))
* 使用了 reduceRight, 从右开始执行
* @param {多个函数, 逗号隔开}
* @return {函数}
*/
export default function compose(...funcs){
if(funcs.length === 0){
return arg => arg
}
if(funcs.length === 1){
return funcs[0]
}
const last = funcs[funcs.length - 1]
const rest = funcs.slice(0,-1)
return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
}
`</pre>
关键在于 reduceRight 可以传入初值
### createStore(reducer, [initialState])
<pre>`import isPlainObject from 'lodash/isPlainObject'
import $$observable from 'symbol-observable'
export var ActionTypes = {
INIT: '@@redux/INIT'
}
export default function createStore(reducer, preloadState, enhancer){
var currentReducer = reducer
var currentState = preloadState
var currentListeners = []
var nextListeners = currentListeners
var isDispatching = false
}
function ensureCanMutateNextListeners(){
if(nextListeners === currentListeners){
nextListeners = currentListeners.slice()
}
}
function getState(){
return currentState
}
function subscribe(listener){
if(typeof listener !== 'function'){
throw new Error('Expected listener to be a function')
}
var isSubscribed = true
ensureCanmutateNextListener()
nextListeners.push(listener)
return function ubsubscribe(){
if(!isSubscribe){
return
}
isSubscribe = false
ensureCanMutateNextListeners()
var index = nextListeners.indexOf(listener)
nextListeners.splice(index,1)
}
}
function dispatch(action){
if(isPlainObecjt(action)){
throw new Error('Action must be plain objects ' + 'Use custom middleware for async action')
}
if(typeof action.type === 'undefined'){
throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?')
}
if(isDispatching){
throw new Error('Reducers may not dispatch actions.')
}
try{
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
var listeners = currentListeners = nextListeners
for(var i = 0; i< listeners.length, i++){
listeners[i]()
}
return action
}
function replaceReducer(nextReducer){
if(typeof nextReducer !== 'function'){
throw new Error('Expected the nextReducer to be a function')
}
currentReducer = nextReducer
dispatch({type:ActionTYpes.INIT})
}
### combineReudcers(reducers)
`</pre>
import { combineReducers } from 'redux'
import counterReducer from './counterReducer'
import todosReducer from './todosReducer'
const rootReducer = combineReducers({
counter: counterReducer, // <--- 键名是 state 中的属性, 键值是对应 reducer 函数名
todos: todosReducer
})
export default rootReducer
<pre>`
如果提高需求
`</pre>
state
├── counter: 0
├── todo
├── optTime: []
├── todoList: [] # 这其实就是原来的 todos!
<pre>`
对应的 reducers 是:
`</pre>
reducers/
├── index.js <-------------- combineReducers (生成 rootReducer)
├── counterReducer.js
├── todoReducers/ <--------- combineReducers
├── index.js
├── optTimeReducer.js
├── todoListReducer.js
<pre>`
`</pre>
/* reducers/index.js */
import { combineReducers } from 'redux'
import counterReducer from './counterReducer'
import todosReducers from './todosReducer'
const rootReducer = combineReducers({
counter: counterReducer,
todos: todosReducers
})
export default rootReducer
=================================================
/* reducers/todosReducers/index.js */
import { combineReducers } from 'redux'
import optTimeReducer from './optTimeReducer'
import todoListReducer from './todoListReducer'
const todosReducers = combineReducers({
optTime: optTimeReducer,
todoList: todoListReducer
})
export default todosReducers
<pre>`
无论 dispatch 哪个 action 都会流通**所有** reducer, 但是由于 reducer 是纯函数, 效率还是会提高.
### BindActionCreator
### applyMiddlware(...middlewares)
先要理解 Middleware, enhancer
Redux 引入中间件机制是为了在 dispatch 前后进行处理
`</pre>
const printStateMiddleware = ({getState}) => next => action => {
console.log('...')
let returnValue = next(action)
console.log('...')
return returnValue
}
<pre>`
实际上最内层
`</pre>
function printStateMiddleware(middlewareAPI){ //中间件内可以使用的 API, 如 getState 与 dispatch
return function(dispatch){ // 传入原 dispatch 的引用
return function(action){
console.log(...)
var returnValue = dispatch(action) // 执行 dispatch 行为, dispatch(action) 返回的还是 action
console.log(...)
return returnValue // 传给下一个中间件的 action
}
}
}
<pre>`
### Store Enhancer
说白了 Store Enhancer 是对生成 store 的 API 的改造, 与 middleware 的最大区别是 middlewere 不修改 store 的 API
改造 store 的 API 就要从 createStore 入口
Redux 的 applyMiddleware 就是一个 Enhancer
`</pre>
import compose from './compose' // 作用就是层层包裹
// 传入中间件
export default function applyMiddleware(...middlewares){
// 传入 createStore
return function(createStore){
// 返回一个函数签名和 createStore 一样的函数, 即返回一个增强版的 createStore
return function(reducer, preloadState, enhancer){
// 用原 createStore 先生成一个 store, 包含 getState, dispatch, subscribe, replaceReducer 四个 API
var store = creataStore(reducer, preloadState, enhancer)
<pre>` var dispatch = store.dispatch // 生成指向原 dispatch的引用
var chain = [] // 存储中间件的数组
//提供给中间件的 API 其实就是 store 的 API
var middlewareAPI = {
getState: store.getStore,
dispatch: (action) => dispatch(action)
}
// 给中间件添加 API
chain = middlewares.map(middleware => middleware(middlewareAPI))
// 串联中间件, 添加中间件的起点 store.dispatch, 返回经过修饰的 dispatch
dispatch = compose(...middlewares)(store.dispatch)
return{
...store, // store 中保留的原 API
dispatch // 用新的 dispatch 覆盖原 dispatch
}
}
}
}
1 | [参考](https://cnodejs.org/topic/57bd23ee1d27b9113348a546) |