Open DeanPaul opened 6 years ago
redux 函数内部包含了大量柯里化函数以及代码组合思想 柯里化函数(curry) 通俗的来讲,可以用一句话概括柯里化函数:返回函数的函数
柯里化函数有什么好处呢? 避免了给一个函数传入大量的参数--我们可以通过柯里化来构建类似上例的函数嵌套,将参数的代入分离开,更有利于调试 降低耦合度和代码冗余,便于复用
找出两个Array中的不同entity
let listA = [1,2,3,null,"20"]
let listB = [1,2,3,5,6,7,10,20,"200"]
const checkDataInArrayFunction = (list) => {
return (target) => {
return list.some(value => value === target)
};
};
const ifDataExistInListA = checkDataInArrayFunction(listA);
const ifDataExistInListB = checkDataInArrayFunction(listB);
listA.filter(value => !ifDataExistInListB(value)) .concat ( listB.filter(value => !ifDataExistInListA(value)) );
const compose = (f, g) => {
return (x) => {
return f(g(x));
};
};
// 还可以再简洁点
const compose = (f, g) => (x) => f(g(x));
通过这样函数之间的组合,可以大大增加可读性,效果远大于嵌套一大堆的函数调用,并且我们可以随意更改函数的调用顺序
思考一下怎样写才能支持动态参数? reduce?
它是一个工具类,所以先说明它
//参数reducers为Object
export default function combineReducers(reducers) {
// 第一次筛选,筛选掉reducers中不是function的键值对
var reducerKeys = Object.keys(reducers);
var finalReducers = {}
for (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i];
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
var finalReducerKeys = Object.keys(finalReducers)
// 二次筛选,判断reducer中传入的值是否合法(!== undefined)
// 获取筛选完之后的所有key
var shapeAssertionError
try {
// assertReducerSanity函数用于遍历finalReducers中的reducer,检查传入reducer的state是否合法
assertReducerSanity(finalReducers)
} catch (e) {
shapeAssertionError = e
}
// 返回一个function。该方法接收state和action作为参数
return function combination(state = {}, action) {
// 如果之前的判断reducers中有不法值,则抛出错误
if (shapeAssertionError) {
throw shapeAssertionError
}
var hasChanged = false
var nextState = {}
// 遍历所有的key和reducer,分别将reducer对应的key所代表的state,代入到reducer中进行函数调用
for (var i = 0; i < finalReducerKeys.length; i++) {
var key = finalReducerKeys[i]
var reducer = finalReducers[key]
// 要求传入的Object参数中,reducer function的名称和要和state同名的原因
var previousStateForKey = state[key]
var nextStateForKey = reducer(previousStateForKey, action)
// 如果reducer返回undefined则抛出错误
if (typeof nextStateForKey === 'undefined') {
var errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
// 将reducer返回的值填入nextState
nextState[key] = nextStateForKey
// 如果任一state有更新则hasChanged为true
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
}
return hasChanged ? nextState : state
}
}
})
}
使用场景是什么? 当你需要把 action creator 往下传到一个组件上,却不想让这个组件觉察到 Redux 的存在,而且不希望把 Redux store 或 dispatch 传给它 实际是封装Action成普通props的样子(让组件无法感知到dispatch)
function bindActionCreator(actionCreator, dispatch) {
return (...args) => dispatch(actionCreator(...args))
}
// bindActionCreators期待一个Object作为actionCreators传入,里面是 key: action
export default function bindActionCreators(actionCreators, dispatch) {
// 如果只是传入一个action,则通过bindActionCreator返回被绑定到dispatch的函数
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
}
// 遍历并通过bindActionCreator分发绑定至dispatch
var keys = Object.keys(actionCreators)
var boundActionCreators = {}
for (var i = 0; i < keys.length; i++) {
var key = keys[i]
var actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
return boundActionCreators
}
提供一套规则的数据库 getState是获取数据库的接口 dispatch是更新数据库的接口 subscribe是注册在store上listener的接口,listener会在任何dispatch之后执行 reducer像是一组暖气片,当dispatch发生时,必然会携带一个Action,Action是固定格式{type:''} ,当Action的type 匹配到某个暖气片时,执行该暖气片携带的函数,此函数更新store,也就是数据库
然后我们看源代码
export default function createStore(reducer, preloadedState, enhancer) {
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
//可以不传初始的state,第二个参数就是enhancer的
enhancer = preloadedState
preloadedState = undefined
}
//如果有传入合法的enhance,则通过enhancer再调用一次createStore
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
//实际就是把createStore这件事在applyMiddleware里面做,转移了锅
return enhancer(createStore)(reducer, preloadedState)
}
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false //是否正在dispatch
//返回当前state
function getState() {
return currentState
}
//浅拷贝currentListeners
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
//// 注册listener,同时返回一个取消事件注册的方法。当调用store.dispatch的时候调用listener
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected listener to be a function.')
}
let isSubscribed = true
ensureCanMutateNextListeners()
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
function dispatch(action) {
//dispatch方法接收的action必须是个对象,而不是方法
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
//Action必须有type属性
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
// 调用dispatch的时候只能一个个调用,通过dispatch判断调用的状态
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
const listeners = currentListeners = nextListeners
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
//用处:动态注入reducer
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}
currentReducer = nextReducer
// the initial state tree. 初始化每个reducer的init state
dispatch({ type: ActionTypes.INIT })
}
function observable() {
const outerSubscribe = subscribe
return {
subscribe(observer) {
if (typeof observer !== 'object') {
throw new TypeError('Expected the observer to be an object.')
}
function observeState() {
if (observer.next) {
observer.next(getState())
}
}
observeState()
const unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
[$$observable]() {
return this
}
}
}
// 返回以 dispatch 和 getState 作为参数的action
export default function thunkMiddleware({ dispatch, getState }) {
return next => action => {
if (typeof action === 'function') {
return action(dispatch, getState);
}
return next(action);
};
}
//写不下去了 函数式编程不好说
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.dispatch
let chain = []
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
柯里化函数(curry) 代码组合(compose)
combineReducers bindActionCreator
createStore thunkMiddleware applyMiddleware
react-redux Provider connect