1. 核心概念及工作流程
2. reducer解析
reducer格式为: (preState, action) => nextState
export default function combineReducers(reducers) {
return function combination(state = {}, action) {
let nextState = {}
let hasChanged = false
for(const key in reducers) {
const reducer = reducers[key]
nextState[key] = reducer(state[key], action)
hasChanged = hasChanged || nextState[key] !== state[key]
}
hasChanged = hasChanged || Object.keys(nextState).length !== Object.keys(state).length
return hasChanged ? nextState : state
}
}
3. 中间件的设计
- 上一个函数的返回值是下一个函数的参数
- 多个函数进行聚合返回一个新的函数
function compose(...funcs) {
if(funcs.length === 0) {
return arg => arg
}
if(funcs.length === 0) {
return funcs[0]
}
return funcs.reduce((a, b) => {
(...args) => a(b(...args))
})
}
4. 源码核心逻辑
function createStore(reducer, preloadedState) {
// 约束reducer参数类型
if(typeof reducer !== 'function') throw new Error('reducer必须是函数')
// store对象存储状态
var currentState = preloadedState
// 存放订阅者函数
var currentListeners = []
// 获取状态
function getState() {
return currentState
}
// 触发action
function dispatch(action) {
// 判断action是否是对象
if(!isPlainObject(action)) throw new Error('action必须是对象')
// 判断对象中是否具有type属性
if(typeof action.type === 'undefined') throw new Error('action对象中必须要有type属性')
currentState = reducer(currentState, action)
// 循环数组,调用订阅者
for(var i = 0; i < currentListeners.length; i++) {
// 获取订阅者
var listener = currentListeners[i]
// 调用订阅者
listener()
}
}
// 订阅状态
function subscribe(listener) {
currentListeners.push(listener)
}
return {
getState,
dispatch,
subscribe
}
}
function isPlainObject(obj) {
// 排除基本数据类型和null
if(typeof obj !== 'obj' || obj === null) return false
// 区分数组和对象,原型对象对比的方式
var proto = obj
while(Object.getPrototypeOf(proto) != null) {
proto = Object.getPrototypeOg(proto)
}
return Object.getPrototypeOg(proto) === proto
}
5. react-redux核心逻辑实现
// 1. 创建context对象
const Context = React.createContext()
// 2. Provider传递value
export function Provider({ store, children }) {
return <Context.Provider value={store}>{children}</Context.Provider>
}
// 3. 后代消费Provider传递value, 类组件
// useContext 只能用在类组件或者自定义hook中
// Consumber 没有组件限制
export const contect = (mapStateToProps, mapDispatchToProps) => (WrapperComponent) => (props) => {
const store = useContext(Context)
const { getState, dispatch, subscribe } = store
const stateProps = mapStateToProps(getState())
let dispatchProps = { dispatch }
if(typeof mapDispatchToProps === 'function') {
dispatchProps = mapDispatchToProps(dispatch)
}
const forceUpdate = useForceUpdate()
useLayoutEffect(() => {
const subscribe = subscribe(() => {
forceUpdate()
})
return () => {
subscribe()
}
}, [subscribe])
return <WrapperComponent {...props} {...stateProps} {...mapDispatchToProps} />
}
function useForceUpdate() {
const [state, setState] = useState(0)
const update = useCallback(() => {
setState(prev => prev + 1)
})
return update
}
// --------------- 函数组件 ---------------
// 获取状态值
export function useSelector(selector) {
const store = useContext(Context)
const { getState, subscribe } = store
const selectedState = selector(getState())
const forceUpdate = useForceUpdate()
useLayoutEffect(() => {
const subscribe = subscribe(() => {
forceUpdate()
})
return () => {
subscribe()
}
}, [subscribe])
return selectedState
}
// 获取更新方法dispatch
export function useDispatch(selector) {
const store = useContext(Context)
const { dispatch } = store
return dispatch
}